Anotaciones BeforeClass y AfterClass
En este episodio nos centramos en dos anotaciones más: BeforeClass y AfterClass. La primera sirve para ejecutar código antes de cualquier prueba en una clase. AfterClass lo mismo pero después. Ambas se suelen usar típicamente para preparar recursos compartidos que son costosos de inicializar y que, por lo tanto, preferiríamos instanciar una única vez antes de lanzar toda la suite de tests, pero que queremos reutilizar a lo largo de todos los casos de prueba que se ejecutan dentro de una clase, reservando el AfterClass para poder limpiar ese recurso si hace falta. En este vídeo lo vemos dentro de un flujo de ejecución y lo comparamos con Before y After.
BeforeClass y AfterClass son dos anotaciones que se comportan como Before y como After, pero que tienen la particularidad de que sólo se van a ejecutar una vez. BeforeClass se va a ejecutar antes de cualquier prueba unitaria que se ejecute dentro de la clase y AfterClass se va a ejecutar después de cualquier otra prueba que se haya ejecutado.
Son anotaciones que, por lo tanto, nos van a permitir inicializar toda una clase de test, y limpiar toda una clase de test. A menudo las podemos usar para instanciar de forma global para todos los casos de un test un recurso costoso de inicializar, para no ralentizar demasiado toda una suite de test. Podría ser el caso de una conexión que hay que establecer para completar un test de integración. Tal vez levantar un navegador o todo un cliente de bases de datos en el @Before
sea muy costoso. Podríamos usar un @BeforeClass
para mantener el recurso cargado al inicio del test, y limpiarlo en el @AfterClass
una vez que ya no quedan tests que vayan a hacer uso de él.
Una cosa que tienes que tener en cuenta con este método es que es estático, así que si tienes que manipular algún atributo que quieras que sea accesible desde los propios tests, tendrás que tener esto en cuenta y declarar los atributos también como estáticos.
Dentro del ciclo de vida de ejecución, en su forma más simple un test anotado como BeforeClass
y AfterClass
tendría la siguiente forma:
public class LifecycleTest {
@BeforeClass
public static void setUpClass() {
DatabaseManager.getInstance().connect();
}
@AfterClass
public static void tearDownClass() {
DatabaseManager.getInstance().stop();
}
@Test
public void testCursor() {
Cursor db = DatabaseManager.getInstance().cursor();
assertNotNull(db);
}
}
En un caso más avanzado, vamos a imprimir una salida en cada uno de los métodos del ciclo de vida para ver su ejecución.
public class LifecycleTest {
@Before
public void setUp() {
System.out.println("before");
}
@After
public void tearDown() {
System.out.println("after");
}
@Test
public void testUno() {
System.out.println("test - uno");
}
@Test
public void testDos() {
System.out.println("test - dos");
}
@BeforeClass
public static void setUpClass() {
System.out.println("beforeClass");
}
@AfterClass
public static void tearDownClass() {
System.out.println("afterClass");
}
}
Al ejecutar esto, obtenemos lo siguiente:
beforeClass
before
test - uno
after
before
test - dos
after
afterClass
En este caso, vemos que la primera y la última línea se corresponde, respectivamente, con el BeforeClass
y con el AfterClass
. Se ejecutan antes y después y envuelven todo lo que hagamos entre medias dentro de la clase. Dentro, tenemos los dos grupos de tres líneas before-uno-after y before-dos-after, como ya vimos en la lección sobre Before y After.
Desplegar transcripción del episodio
Nos queda poco para terminar, realmente, tampoco le queda mucho ya a JUnit por contar, pero bueno, principalmente en los dos o tres vídeos que quedan me voy a centrar en explicar otra serie de utilidades que trae JUnit, que conviene conocer sobre todo de cara a hacer pruebas unitarias más rápidamente y que funcionen mejor, y a tener que escribir menos código principalmente.
BeforeClass y AfterClass son dos anotaciones que se comportan como Before y como After, pero que tienen la particularidad de que sólo se van a ejecutar una vez. BeforeClass se va a ejecutar antes de cualquier prueba unitaria que se ejecute dentro de la clase y AfterClass se va a ejecutar después de cualquier otra prueba que se haya ejecutado. Es decir, que primero vendría el BeforeClass, y luego vendría el set Before-Test-After, Before-Test-After, Before-Test-After, para terminar con un AfterClass, ¿vale? ese BeforeClass y AfterClass como digo solo se va ejecutar una única vez por cada uno.
Entonces, ¿de qué forma los podemos aprovechar? Ya vimos que podríamos utilizar Before y After para resetear la calculadora e inicializar una nueva calculadora, pero podemos hacerlo para cargar un recurso una única vez. Imaginemos que estamos intentando probar un recurso del que obtener acceso a él es complicado porque lleva mucho tiempo, es un objeto muy pesado de construir... pensemos a lo mejor en un objeto que dependa de conexiones... bueno, si depende de conexiones ya no es tan prueba unitaria, pero que en general sea un objeto complicado de construir y que no queramos estar todo el rato creando instancias, tirando instancias porque a lo mejor requiere bastante memoria su tiempo inicializar se va a ejecutar su constructor nos vendría bien una forma de por ejemplo instanciarlo una única vez y reutilizarlo en cada una de las clases. Y eso es lo que podemos hacer en este caso. Por ejemplo, recordáis que yo a mi calculadora le puse un método llamado clear. Pues podríamos hacer un BeforeClass que nos cree la calculadora, y un Before que llame al método clear(). De este modo, la calculadora sólo se inicializa una única vez, pero no obstante se va a limpiar siempre antes de cada prueba para asegurarnos de que queda limpia, y que a la prueba unitaria, al test, no le entra sucio, ¿vale? Que queda limpio y que no tiene ejecuciones anteriores, que es como si estuviese recién inicializada. Así que voy a hacer una prueba... bueno, voy a hacer mi cambio, más bien, introduciendo mi anotación BeforeClass, y la voy a llamar public void beforeClass, porque no tengo nada de imaginación, y voy a decir que calc es new Calculadora(), ¿vale? Para que veáis que esto funciona realmente voy a escribir por pantalla el mensaje... bueno, si escribo bien, claro... voy a escribir por pantalla el mensaje beforeClass().
Y ahora lo que voy a hacer es que en mi before(), en vez de llamar a calc = new Calculadora(), voy a llamar simplemente al método calc.clear(), de modo que cuando se ejecute la prueba sea como si fuese limpia, ¿vale? Se supone que el método clear está bien hecho, borra la cosa que haya en memoria y tal... imaginemos que está bien hecho, ¿vale? que debe estarlo. Y ya puestos vamos a hacer un AfterClass también para poner a modo de colofón un afterClass que no haga nada pero que ponga... bueno mira ya se llama clic en el after(), bah, pues ya no se llama a clear(). Vamos a ver que se imprima simplemente un afterClass(), para que veamos cómo solamente se ejecuta una única vez.
Y ya lo tenemos realmente. Tampoco hay mucho que contar vamos a ejecutarlo para ver que esto funciona y todo lo demás. Le voy a dar a Run.
Y vaya la he pifiado en algo porque debe ser static, vale bueno... lo he hecho accidentalmente pero la vez se podría decir que es un poco intencional en cierto modo porque la mayoría de veces os vais a olvidar, espero... vamos no sé. No sé si sois tan torpes como yo programando pero, vaya, tiene que ser static, fíjate tú que cosas, siempre se me olvida, no os preocupéis por esto. Pero lo que tengo que hacer static es el AfterClass, no cualquier otro método.
Ay, y he dejado aquí esto de la prueba anterior, que se me ha olvidado quitarlo... vamos a quitarlo a ver si corre ahora... iba a ser un vídeo corto y fíjate qué largo se va a hacer al final. Vale en un principio la prueba corre pero lo interesante no está aquí en CalculadoraTest ni en la prueba unitaria, está en lo que se ha escrito en la consola. En la consola veis que primero se ejecuta el BeforeClass, después se ejecuta un before y un after de una prueba unitaria que francamente no sé cuál es, será de alguna que no tenga puesto... por ejemplo... voy a hacer que se pongan todos los printlns, porque si no esto es un cacao bastante grande... el Div, por ejemplo... div() con exception.
Ahora lo voy a repetir para que se vea mejor. Entonces tenemos BeforeClass, Before-Div-After, que esto sería una prueba, Before-Sub-After, que esto sería otra, Before-Div-After, que esto sería otra y finalmente Before-AnsSum-After, que sería otra. A modo de colofón tenemos este AfterClass, que básicamente sirve para que todos aquellos recursos que ya hemos cargado en el Before, por ejemplo, pues los podamos limpiar. Imaginad que se trata de un método que requiere que llamemos... yo que sé, a un método tipo dispose(), se trata de un objeto que tiene que tener un dispose() o algo por el estilo, para hacer limpieza... pues en el AfterClass sería un buen momento para decir oye, límpiate
.
Entonces, en resumidas cuentas, me ha quedado un vídeo demasiado largo para una tontería tan grande. BeforeClass y AfterClass. Recordad que el método tiene que ser estático: public static void, para que se pueda ejecutar, ¿vale? Cualquier cosa que pongáis aquí se va a ejecutar al principio de la prueba y es un buen momento para inicializar recursos. Esto no es lo mismo que Before y After la principal diferencia es que el Before y After se van a ejecutar en cada prueba y que además no son estáticos pero viene bien conocerlo.