2008-12-10 12 views
60

¿Debo I a la unidad de constructores de prueba? Digamos que tengo un constructor como este:¿Es importante probar la unidad de un constructor?

 IMapinfoWrapper wrapper; 
     public SystemInfo(IMapinfoWrapper mapinfoWrapper) 
     { 
      this.wrapper = mapinfoWrapper; 
     } 

¿Tengo que escribir una prueba de unidad para este construtor? No tengo getters para la variable wrapper, así que no necesito probar eso.

Respuesta

76

La prueba de unidades se trata de probar los estados públicos, los comportamientos y las interacciones de sus objetos.

Si simplemente establece un campo privado en su constructor, ¿qué hay para probar?

No se moleste en probar sus detectores y mutadores simples. Eso es una tontería, y no ayuda a nadie.

+25

Si su constructor tiene, por ejemplo, un if (condición), necesita para probar ambos flujos (verdadero, falso). Si su constructor hace algún tipo de trabajo antes de la configuración. Debe verificar que el trabajo esté hecho. – graffic

+1

¿Qué sucede si tienes un 'checkArgumnt' en el constructor (quizás para probar que el objeto es nulo o no)? ¿Vale la pena probar eso? – noMAD

+1

Sí, a menudo vale la pena probar constructores con su propio comportamiento complejo. – yfeldblum

8

No. Su funcionalidad será probada por cada prueba unitaria de la clase.

+0

Cierto, ni siquiera pensé en eso. * golpea la frente * –

+10

No todos, si hay varios constructores o varios flujos de control dentro de él. –

26

Sí. Si tienes lógica en tu constructor, debes probarla. Simplemente establecer propiedades no es lógica IMO. Condicionales, flujo de control, etc. IS lógica.

Editar: Probablemente deberías probar cuando IMapinfoWrapper es nulo, si esa dependencia es necesaria. Si es así, entonces eso es lógica y debe tener una prueba que capte su ArgumentNullException o lo que sea ... sus pruebas son especificaciones que definen cómo se comporta el código. Si arroja una ArgumentNullException, entonces eso debe especificarse en una prueba.

+2

Nunca puse ninguna lógica en mis constructores. Solo setters. –

+0

@BrianGenisio, gracias por la sugerencia, acabo de agregar algunas pruebas y código ArgumentNullException a mi aplicación ... por alguna razón, nunca lo tuve ... – CaffGeek

0

Creo en la cobertura del 100%. También una cobertura del 100% no simplemente probando interacciones simples burlándose o simplemente configurando y obteniendo cosas, sino más pruebas de integración/aceptación que verifican la funcionalidad. Entonces, si terminas escribiendo pruebas de integración/aceptación realmente buenas, debes llamar a todos tus constructores (y a métodos simples como setters y getters).

+1

La cobertura del 100% es una quimera y cualquiera que le diga lo contrario le vende una nueva y brillante herramienta de prueba. ;) Yo chico ... más o menos. –

+0

Puede ser un problema en los sistemas heredados, pero si está comenzando un nuevo proyecto desde cero, en mi opinión, el 100% es el único camino a seguir. He trabajado en sistemas con una cobertura del 100%. Probamos condujo todo. – digiarnie

+0

OK, tenía una cobertura del 100%. Pero, ¿probaste todas las rutas de ejecución? El primero no implica el segundo. – kdgregory

0

¿Qué comportamiento de una instancia de SystemInfo depende del valor de wrapper?

Si algo puede salir mal (por ejemplo, el valor nulo causa rotura) entonces sugiero escribir escenarios que describan cada situación y usarlos para conducir la definición de las pruebas unitarias apropiadas.

Si todos los escenarios terminan dependiendo del estado o el comportamiento de la instancia privada de IMapinfoWrapper, sugeriría escribir pruebas de unidad en esa clase en su lugar.

-1

pruebas unitarias se trata de comprobar rutas de ejecución, algo que a menudo referido como Cyclomatic Complexity

Si no tiene ruta a elegir, no si, ningún bucle, sin GOTO (= P) no es muy útil

+2

No estoy de acuerdo con usted que probar un método sin ningún ifs/loops/gotos no tenga sentido. Siempre hay al menos una ruta de ejecución, y debe probarla incluso si es la única. –

+0

Eric, ¿qué tal probar casos de límites y probar valores representativos entre los límites? Por ejemplo, las entradas de 0 y 1 se pueden considerar casos límite para una función de raíz cuadrada, porque allí los valores de entrada y salida son iguales. Por lo tanto, pruebe, por ejemplo, -10, -1, -0.5, 0, 0.5, 1 y 10. O también realice pruebas en todo el rango. Si su función debería funcionar para entradas de hasta 4096, intente con 4095 y 4097 ... –

11

P: Si está configurando una variable miembro en el constructor, ¿por qué la configura?

A: Debido a que tiene una prueba de unidad defectuosa que solo se puede pasar, configurándola en el constructor.

Si usa esta lógica, donde solo escribe código para hacer pasar una prueba de unidad (Desarrollo conducido por prueba), entonces ya tendrá la respuesta a su pregunta.

0

No, a menos que esté escribiendo un compilador, porque solo estaría probando que el compilador podría generar código para hacer asignaciones, lo que normalmente no tiene sentido.

Ahora, en una situación más habitual, si desea hacer algo más con el envoltorio, entonces tal vez haya un punto. Por ejemplo, puedes lanzar una ArgumentNullException si intentas pasar un nulo, y en teoría, eso podría tener una prueba unitaria. Incluso entonces, el valor de la prueba es bastante mínimo.

Personalmente, casi nunca pruebo explícitamente los constructores. Si son lo suficientemente complicados como para necesitar pruebas, tiendo a sentir que el código está un poco mal.

0

Si el constructor contiene algo de lógica, como inicializar una clase, creo que deberías probar el mismo constructor. O puede hablar con el desarrollador de que poner la inicialización en el constructor reducirá la capacidad de prueba del código bajo prueba.

3

En muchos entornos regulados por la FDA, el código más crítico debe ser probado al 100% ... incluida la construcción de clases. Por lo tanto, la prueba de los constructores a veces es necesaria independientemente del razonamiento o no para probarlos. Además, las compañías que utilizan herramientas de análisis estático deberán asegurarse de que TODOS los datos de una clase estén inicializados correctamente para no tener errores, aunque el código puede ejecutarse sin problemas y sin errores. Por lo general, la inicialización de los miembros de datos se realiza en el constructor ... solo como algo para pensar.

+0

¿tiene alguna referencia para los requisitos de la FDA? –

1

También es necesario probar accesos y mutadores a menos que el desarrollador se haya asegurado de que no se puede cambiar la lógica de estado. Por ejemplo, si uno usa el patrón de diseño para un Singleton, a menudo se usan accedores o propiedades, y si la clase no se inicializa, se hace desde el acceso, ya que el constructor es privado. En C++, uno puede hacer que sus funciones sean constantes o estáticas en las cuales los datos de los miembros de la clase no se pueden cambiar. (Nota: incluso el uso de estática es un poco arriesgado ya que esas variables suelen ser globales.) Sin embargo, sin una prueba, si alguien no utiliza medidas preventivas, ¿cómo puede garantizar con 100% de precisión que lo que está escrito no puede convertirse en un fracaso ¿hora? El mantenimiento no es infalible.

2

Depende.

No me molestaría en escribir una prueba de constructor dedicada para algo tan simple como el ejemplo que usted dio.

Sin embargo, si tiene pruebas lógicas en el constructor, como la validación de un parámetro, entonces sí, absolutamente. Aunque, al igual que el póster original, no trabajo en el constructor si es posible, es común que se deba realizar la validación del parámetro. En este caso, es inevitable evitar que el constructor haga algún trabajo. Si hay lógica en el constructor, siempre existe la posibilidad de que pueda estar mal, por lo tanto, lo trato como cualquier otra llamada a método y lo pruebo adecuadamente.

4

Debería probar el constructor. Si tiene un constructor predeterminado, debe probar que se puede invocar. ¿Qué sucede si más adelante se cambia la clase? ¿Tal vez se convierta en un singleton o se elimine el constructor predeterminado a favor de uno que requiera parámetros? En ese caso, la prueba no debe alertar sobre ese cambio (para que la clase o la prueba se puedan corregir para cumplir con el nuevo requisito).

La presencia de un constructor predeterminado es un requisito que debe tener una prueba. Incluso si todo lo que hace el constructor es establecer miembros privados que se probarán en otra parte, se debe probar el hecho de que hay un constructor sin parámetros.

1

Creo que la respuesta a esto es "Sí".

Hay un montón de código que supone, horriblemente, un estado de objeto inicializado, en lugar de una referencia nula, a menudo cuando no hay valores explícitos asignados en el constructor.

Estoy feliz de tener las pruebas de constructor que se rompen para alertarme cuando se han cambiado los valores de miembros públicos inicializados. Se trata de pruebas defensivas. Soy pragmático y me alegra más tener pruebas que no, y las elimino cuando no se muestran útiles o útiles.

1

Estoy probando constructores cuando contienen lógica, p. validación o configuración condicional un estado privado. Los errores de validación terminan en una excepción lanzada desde el constructor. La ejecución exitosa termina en una creación de objeto que exhibe un comportamiento específico dependiendo del estado que se estableció en el constructor. De cualquier manera, requiere pruebas. Pero las pruebas de constructor son aburridas porque todas tienen el mismo aspecto: invocan al constructor y hacen una afirmación. Las declaraciones de métodos de prueba a menudo ocupan más espacio que toda la lógica de prueba ... Así que escribí una biblioteca de pruebas simple que ayuda a escribir pruebas declarativas para los constructores: How to Easily Test Validation Logic in Constructors in C#

He aquí un ejemplo en el que estoy probando siete casos de prueba en un constructor de una clase:

[TestMethod] 
public void Constructor_FullTest() 
{ 

    IDrawingContext context = new Mock<IDrawingContext>().Object; 

    ConstructorTests<Frame> 
     .For(typeof(int), typeof(int), typeof(IDrawingContext)) 
     .Fail(new object[] { -3, 5, context }, typeof(ArgumentException), "Negative length") 
     .Fail(new object[] { 0, 5, context }, typeof(ArgumentException), "Zero length") 
     .Fail(new object[] { 5, -3, context }, typeof(ArgumentException), "Negative width") 
     .Fail(new object[] { 5, 0, context }, typeof(ArgumentException), "Zero width") 
     .Fail(new object[] { 5, 5, null }, typeof(ArgumentNullException), "Null drawing context") 
     .Succeed(new object[] { 1, 1, context }, "Small positive length and width") 
     .Succeed(new object[] { 3, 4, context }, "Larger positive length and width") 
     .Assert(); 

} 

de esta manera, puede probar todos los casos relevantes para mi constructor sin tener que escribir mucho.

Cuestiones relacionadas