¿Debo inicializar los campos de clase en una declaración como esta?
public class SomeTest extends TestCase
{
private final List list = new ArrayList();
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
¿O en setUp () así?
public class SomeTest extends TestCase
{
private List list;
@Override
protected void setUp() throws Exception
{
super.setUp();
this.list = new ArrayList();
}
public void testPopulateList()
{
// Add stuff to the list
// Assert the list contains what I expect
}
}
Tiendo a usar el primer formulario porque es más conciso y me permite usar campos finales. Si no necesito utilizar el método setUp () para la configuración, ¿debería seguir utilizándolo y por qué?
Aclaración:
JUnit creará una instancia de la clase de prueba una vez por método de prueba. Eso significa list
que se creará una vez por prueba, independientemente de dónde lo declare. También significa que no hay dependencias temporales entre las pruebas. Por tanto, parece que no hay ventajas en utilizar setUp (). Sin embargo, las preguntas frecuentes de JUnit tienen muchos ejemplos que inicializan una colección vacía en setUp (), así que supongo que debe haber una razón.
Respuestas:
Si se está preguntando específicamente sobre los ejemplos en las preguntas frecuentes de JUnit, como la plantilla de prueba básica , creo que la mejor práctica que se muestra allí es que la clase bajo prueba debe instanciarse en su método de configuración (o en un método de prueba) .
Cuando los ejemplos de JUnit crean una ArrayList en el método setUp, todos pasan a probar el comportamiento de esa ArrayList, con casos como testIndexOutOfBoundException, testEmptyCollection y similares. La perspectiva que existe es la de alguien que escribe una clase y se asegura de que funcione correctamente.
Probablemente debería hacer lo mismo cuando pruebe sus propias clases: cree su objeto en setUp o en un método de prueba, para que pueda obtener un resultado razonable si lo rompe más tarde.
Por otro lado, si usa una clase de colección Java (u otra clase de biblioteca, para el caso) en su código de prueba, probablemente no sea porque quiera probarlo, es solo parte del dispositivo de prueba. En este caso, puede asumir con seguridad que funciona según lo previsto, por lo que inicializarlo en la declaración no será un problema.
Por lo que vale, trabajo en una base de código relativamente grande, desarrollada por TDD y de varios años de antigüedad. Habitualmente inicializamos cosas en sus declaraciones en código de prueba, y en el año y medio que he estado en este proyecto, nunca ha causado un problema. Entonces, hay al menos alguna evidencia anecdótica de que es algo razonable.
fuente
Empecé a investigar y encontré una ventaja potencial de usar
setUp()
. Si se produce alguna excepción durante la ejecución desetUp()
, JUnit imprimirá un seguimiento de pila muy útil. Por otro lado, si se lanza una excepción durante la construcción del objeto, el mensaje de error simplemente dice que JUnit no pudo instanciar el caso de prueba y no ve el número de línea donde ocurrió la falla, probablemente porque JUnit usa la reflexión para instanciar la prueba. clases.Nada de esto se aplica al ejemplo de crear una colección vacía, ya que eso nunca arrojará, pero es una ventaja del
setUp()
método.fuente
Además de la respuesta de Alex B.
Incluso es necesario utilizar el método setUp para crear instancias de recursos en un estado determinado. Hacer esto en el constructor no es solo una cuestión de tiempos, sino que debido a la forma en que JUnit ejecuta las pruebas, cada estado de prueba se borraría después de ejecutar una.
JUnit primero crea instancias de testClass para cada método de prueba y comienza a ejecutar las pruebas después de que se crea cada instancia. Antes de ejecutar el método de prueba, se ejecuta su método de configuración, en el que se puede preparar algún estado.
Si el estado de la base de datos se creara en el constructor, todas las instancias crearían una instancia del estado de la base de datos una después de la otra, antes de ejecutar cada prueba. A partir de la segunda prueba, las pruebas se ejecutarían con un estado sucio.
Ciclo de vida de JUnits:
Con algunos registros en una prueba con dos métodos de prueba, obtienes: (el número es el código hash)
fuente
@BeforeClass
en JUnit 4.En JUnit 4:
@Before
método para detectar fallas.final
, exactamente como se indica en la pregunta,@Before
para detectar fallas.@BeforeClass
, pero tenga cuidado con las dependencias entre las pruebas.La inicialización en un
@Before
método o método de prueba le permite obtener mejores informes de errores sobre fallas. Esto es especialmente útil para crear instancias de la clase bajo prueba (que puede romper), pero también es útil para llamar a sistemas externos, como el acceso al sistema de archivos ("archivo no encontrado") o la conexión a una base de datos ("conexión rechazada").Es aceptable tener un estándar simple y usarlo siempre
@Before
(errores claros pero detallados) o inicializar siempre en una declaración (conciso pero da errores confusos), ya que las reglas de codificación complejas son difíciles de seguir, y esto no es gran cosa.La inicialización
setUp
es una reliquia de JUnit 3, donde todas las instancias de prueba se inicializaron con entusiasmo, lo que causa problemas (velocidad, memoria, agotamiento de recursos) si realiza una inicialización costosa. Por lo tanto, la mejor práctica fue realizar una inicialización costosasetUp
, que solo se ejecutó cuando se ejecutó la prueba. Esto ya no se aplica, por lo que es mucho menos necesario utilizarlosetUp
.Esto resume varias otras respuestas que entierran el lede, en particular por Craig P. Motlin (pregunta en sí y auto-respuesta), Moss Collum (clase bajo prueba) y dsaff.
fuente
En JUnit 3, sus inicializadores de campo se ejecutarán una vez por método de prueba antes de ejecutar cualquier prueba . Siempre que los valores de campo sean pequeños en la memoria, requieran poco tiempo de configuración y no afecten al estado global, el uso de inicializadores de campo está técnicamente bien. Sin embargo, si no se cumplen, puede terminar consumiendo mucha memoria o tiempo configurando sus campos antes de que se ejecute la primera prueba, y posiblemente incluso quedando sin memoria. Por esta razón, muchos desarrolladores siempre establecen valores de campo en el método setUp (), donde siempre es seguro, incluso cuando no es estrictamente necesario.
Tenga en cuenta que en JUnit 4, la inicialización del objeto de prueba ocurre justo antes de la ejecución de la prueba, por lo que el uso de inicializadores de campo es más seguro y el estilo recomendado.
fuente
En su caso (creando una lista) no hay diferencia en la práctica. Pero generalmente es mejor usar setUp (), porque eso ayudará a Junit a reportar las Excepciones correctamente. Si ocurre una excepción en el constructor / inicializador de una prueba, eso es un error de prueba . Sin embargo, si se produce una excepción durante la configuración, es natural pensar en ello como un problema al configurar la prueba, y junit lo informa de manera adecuada.
fuente
Prefiero la legibilidad primero, que a menudo no usa el método de configuración. Hago una excepción cuando una operación de configuración básica lleva mucho tiempo y se repite dentro de cada prueba.
En ese punto, muevo esa funcionalidad a un método de configuración usando la
@BeforeClass
anotación (optimizar más tarde).Ejemplo de optimización usando el
@BeforeClass
método de configuración: uso dbunit para algunas pruebas funcionales de la base de datos. El método de configuración es responsable de poner la base de datos en un estado conocido (muy lento ... 30 segundos - 2 minutos dependiendo de la cantidad de datos). Carga estos datos en el método de configuración anotado@BeforeClass
y luego ejecuto de 10 a 20 pruebas con el mismo conjunto de datos en lugar de volver a cargar / inicializar la base de datos dentro de cada prueba.Usar Junit 3.8 (extender TestCase como se muestra en su ejemplo) requiere escribir un poco más de código que simplemente agregar una anotación, pero la "ejecución una vez antes de la configuración de la clase" aún es posible.
fuente
Dado que cada prueba se ejecuta de forma independiente, con una instancia nueva del objeto, no tiene mucho sentido que el objeto de prueba tenga un estado interno excepto el compartido entre
setUp()
una prueba individual ytearDown()
. Esta es una de las razones (además de las razones que dieron otros) por la que es bueno utilizar elsetUp()
método.Nota: ¡Es una mala idea que un objeto de prueba JUnit mantenga un estado estático! Si utiliza una variable estática en sus pruebas para cualquier otra cosa que no sea el seguimiento o el diagnóstico, está invalidando parte del propósito de JUnit, que es que las pruebas pueden (y pueden) ejecutarse en cualquier orden, cada prueba ejecutándose con un Estado fresco y limpio.
Las ventajas de usarlo
setUp()
es que no tiene que cortar y pegar código de inicialización en cada método de prueba y que no tiene código de configuración de prueba en el constructor. En tu caso, hay poca diferencia. La simple creación de una lista vacía se puede hacer de forma segura como la muestra o en el constructor, ya que es una inicialización trivial. Sin embargo, como usted y otros han señalado, cualquier cosa que pueda generar un errorException
debe hacersesetUp()
para que obtenga el volcado de pila de diagnóstico si falla.En su caso, donde solo está creando una lista vacía, haría lo mismo que está sugiriendo: Asignar la nueva lista en el punto de declaración. Especialmente porque de esta manera tienes la opción de marcarlo
final
si esto tiene sentido para tu clase de prueba.fuente
final
embargo, la ventaja de se menciona en la pregunta.Los valores constantes (usos en accesorios o aserciones) deben inicializarse en sus declaraciones y
final
(como nunca cambian)el objeto bajo prueba debe inicializarse en el método de configuración porque podemos configurar las cosas. Por supuesto, es posible que no establezcamos algo ahora, pero podríamos configurarlo más tarde. Crear instancias en el método init facilitaría los cambios.
las dependencias del objeto bajo prueba si se simulan, ni siquiera deberían ser instanciadas por usted mismo: hoy los marcos simulados pueden instanciarlo por reflexión.
Una prueba sin dependencia para simular podría verse así:
Una prueba con dependencias para aislar podría verse así:
fuente