2011-01-05 10 views
7

estoy tratando de probar una unidad de método en una clase que inicializa algunos campos privados:¿Cómo probar el método vacío que solo modifica las variables de miembros de la clase privada?

public void init(Properties props) throws Exception { 

    this.language = props.getProperty(Constants.LANGUAGE,Constants.LANGUAGE_DEFAULT); 
    this.country = props.getProperty(Constants.COUNTRY,Constants.COUNTRY_DEFAULT); 

     try { 
      this.credits = Integer.valueOf(props.getProperty(Constants.CREDITS_OPTION_NAME, Constants.CREDITS_DEFAULT_VALUE)); 
     } catch (NumberFormatException e) { 
      throw new Exception("Invalid configuration: 'credits' does not contain a valid integer value.", e); 
     } 
     //rest of method removed for sake of simplicity 
    } 

Mi dilema es que quiero afirmar que el idioma, el país y créditos campos se han establecido después de llamar a init, sin embargo, son privados sin métodos de acceso público. Veo que hay dos soluciones para probar esta:

  1. hacer que los métodos públicos para acceder a los campos privados, a continuación, llamar a estos métodos después de probar el método init.
  2. Haga que la prueba de la unidad simplemente llame al método init, y suponga que todo funcionó correctamente, no se lanzó ninguna excepción.

¿Cuál cree que es la forma ideal de probar este método?

+0

¿Hay alguna razón por la que nadie sugirió agregar otra prueba que llama al colocador, luego llama a "otro método en la misma clase que necesita que se establezcan estos campos?" Soy bastante nuevo en TDD y me he inclinado por este tipo de solución en mi propio trabajo, ¿hay algún problema con esto? ¿Sigue siendo una prueba unitaria u otra cosa, como pruebas de integración o algo así? como parece ser sugerido aquí: http://stackoverflow.com/questions/3193257/should-i-test-public-class-function-that-changes-only-internal-state-of-the-obje –

Respuesta

9

Puede usar la reflexión para obtener los valores de campos privados. Por ejemplo:

Field field = YourClass.class.getDeclaredField("language"); 
field.setAccessible(true); //override the access restriction of it being private 
field.get(yourObject); 

Si hay primavera en la ruta de clases, puede utilizar su ReflectionUtils/ReflectionTestUtils.

A veces se argumenta que los campos privados no deben verificarse, y solo el estado público del objeto es el punto de prueba unitaria. Desde esa perspectiva, puede ser mejor exponer a un comprador, o incluso mejor, lanzar una excepción.

Si el objeto no está en estado válido si los campos no están establecidos, entonces la propia aplicación del objeto debe hacer valer su validez, lanzando una excepción.

+0

Gracias, en Al final decidí lanzar una excepción desde mi método init si los valores no eran correctos. –

1

¿Su JUnit llama al método directamente? Luego, la referencia al objeto de propiedad es la misma, debe poder acceder al idioma y al país, para los créditos hacer el recálculo en su JUnit.

El acceso público para métodos privados también es una buena opción.

+0

Ahora que realmente no probaría la clase bajo prueba ¿lo haría ... –

+0

Los métodos de acceso público funcionarían, pero luego estoy exponiendo los valores de campo desde fuera de la clase cuando no es necesario que estén visibles. Estoy totalmente de código de refactorización para que sea más comprobable, pero esto no parece "correcto" en esta situación. –

4

Normalmente trato de evitar las pruebas que dependen de la estructura interna de la clase bajo prueba. Prefiero probar esto probando algún método que luego use estos campos.

Si estás haciendo estricta TDD, ni siquiera debería agregar esos campos hasta que haya un caso de prueba que en realidad se aprovecha de ellos :)

+0

Desafortunadamente estoy probando un código heredado, por lo que no tengo mucha libertad con respecto a los cambios que puedo hacer. –

+0

+1 para "ni siquiera debería agregar esos campos hasta que tenga un caso de prueba" – Raedwald

9

quiero afirmar que el idioma, el país y los campos de créditos se han establecido después de llamar a init

Alguna filosofía: ¿por qué te importa si están configurados correctamente? Si la respuesta es "para que la clase se comporte correctamente", entonces puede probar que se han establecido correctamente al probar el comportamiento posterior esperado. Sin embargo, si configurarlos de manera incorrecta no tiene ningún efecto, son redundantes y debe eliminarlos.

Otro afiche sugirió usar la reflexión para acceder a los campos privados. Aconsejo contra esto; cualquier elemento marcado como privado debe ser un detalle de implementación de la clase y, por lo tanto, no debe probarse directamente. En su lugar, debe probar la API publicada de su clase. Luego tiene la libertad de refactorizarlo fácilmente cambiando los detalles de implementación (privados).

+0

Hay otro método en la misma clase que necesita que se establezcan estos campos, sin embargo, dado que se burla de la llamada al método que se basa en estos campos no informará un error. En este caso, ¿es mejor atrapar los campos como se están configurando en el método init? –

+0

Si no se informara ningún error, los campos no tienen ningún efecto, por lo que recomendaría eliminarlos O, mejor dicho, diferirlos hasta que trabaje en ese método. – Raedwald

+0

En circunstancias normales, se informaría un error, pero en una situación de prueba esas dependencias externas deben ser burladas, por lo que no se generarán errores en el simulacro, pero los campos son realmente necesarios. Establecer los valores de campo solo en el método en el que se usan tendría sentido, pero los valores de los que están establecidos (props) solo están disponibles para el método init. –

1

Personalmente, simplemente verificaría los métodos públicos. Algunas veces necesita verificar las partes internas, pero esto es raro.

BTW: Una alternativa a los captadores públicos es hacer la prueba de la unidad en el mismo paquete y proporcionar captadores locales de paquetes.

Cuestiones relacionadas