Como continuación del post anterior (los voy improvisando) quiero contar aquí algunas cosas que he descubierto, y con las cuáles me he pegado, sobre las pruebas unitarias, la configuración de log4j y el chequeo de "excepciones esperadas".
Estoy desarrollando una aplicación haciendo TDD desde el modelo de datos (os recomiendo este hilo de la lista en español de TDD) y, para ello, elaborando pruebas unitarias para irlo "descubriendo" según vaya necesitando campos, validaciones, etc. En este camino tengo como compañeras de viaje las herramientas de testing que vienen con Grails (versión 1.2.2), tanto las clases para tal propósito, como las funciones de "mock" (artículo recomendado).
Ya he construido unas cuentas pruebas para un par de entidades y, aunque no resultado complicado, me he encontrado con un par de cosas que en los libros que tengo no aparecen y creo pueden resultar de utilidad: el uso de log4j y el chequeo de excepciones.
log4j
Es posible que el problema con el cuál me he encontrado sea debido a "mi desastrosa" configuración de Log4j en el fichero Config.groovy, al uso de STS o a ambas cosas. Mi configuración "estándar":
log4j {
appender.stdout = "org.apache.log4j.ConsoleAppender"
appender.'stdout.layout'="org.apache.log4j.PatternLayout"
rootLogger="error,stdout"
logger {
grails="info,stdout"
org {
grails.spring="info,stdout"
codehaus.groovy.grails.web="info,stdout"
codehaus.groovy.grails.commons="info,stdout"
}
}
}
También existe la posibilidad que, al estar usando test unitarios y, por ello, Grails no "usa todos sus recursos" no esté configurando e inyectando el "log" como debería. El caso es, que cuando ejecutas un test en el IDE la consola te da un mensaje de advertencia:
"log4j:WARN No appenders could be found for logger (org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationInitializer).
log4j:WARN Please initialize the log4j system properly."
Esto, además, "oculta" cualquier otro tipo de información que pretendas mostrar por pantalla (un println por ejemplo) y, la verdad, poco útil se vuelve la consola. He recorrido foros, blogs, listas de correo, etc y no he encontrado nada que me solucionase la papeleta hasta esta mañana. Según he leído esto se debe a como el IDE ejecuta los test unitarios de Grails ya que si uso un terminal con grails test-app todo va bien y no muestra advertencia ninguna. Para forzar al entorno que muestre las trazas se debe inyectar explícitamente en el código con las siguiente líneas:
import org.apache.log4j.*
class VisitaUnitTest extends GrailsUnitTestCase {
def visita
def log
protected void setUp() {
super.setUp();
BasicConfigurator.configure()
LogManager.rootLogger.level = Level.ALL
log = LogManager.getLogger("Visita")
// use groovy metaClass to put the log into your class
Visita.class.metaClass.getLog << {-> log}
visita = new Visita()
...
Podemos ver como le indicamos al "LogManager" que clase queremos trazar y, posteriormente, le inyectamos el objeto "log" construido a la entidad/clase en cuestión. Yo he definido el nivel "Level.ALL" para que muestre todos los mensajes y, efectivamente, en la consola empieza a aparecer todas las operaciones. No desaparece el mensaje de advertencia pero ya podemos "imprimir" información por consola y visualizarla durante la ejecución del test. Curiosamente, si ejecutáis este código desde el terminal, no se toma esta configuración, sino la que tiene el fichero Config.groovy, por lo que se podría decir que, efectivamente, es el IDE el que no "levanta" las configuraciones adecuadas.
Existe un método llamado mockLogging que permite, precisamente, habilitar las trazas en los test para las clases que le digamos pero, ejecutándolas en el IDE, su comportamiento es nulo. Agradecería cualquier tipo de comentario o ayuda sobre este tema.
Chequeo de excepciones esperadas
Uno de los típicos test que se realizan es chequear las excepciones que, a priori, queremos/sabemos que debería arrojar un método en una situación anómala. De esta forma cubrimos ese caso y nos aseguramos que la funcionalidad se comporta tal y como debería.
Para ello me puse a buscar por los libros que tengo pero no encontraba nada. Cierto que grails tiene por detrás JUnit 3 y, por tanto, se puede hacer uso de sus posibilidades. Además, también tenemos a Spring que proporciona alguna "anotación" para este caso. También hoy, día de encontrar soluciones, he dado con la forma de probar esto. Lo mejor es que os muestre un ejemplo:
public void testNoGuardarVisitaInValidaArrojaExcepcion() {
shouldFail(MissingPropertyException) {
visita.campoquenoexiste = ""
visita.save()
}
}
Podemos usar "shouldFail" para indicar que excepción esperamos, con la que debería fallar el código, que tiene en su interior. El resultado final es igual que el conocido "@test(excepted=..." o "@ExpectedException". El test pasa si la excepción arrojada es la indicada. Así de fácil.
Igual que dije antes, espero comentarios/quejas/dudas/críticas sobre esto. Siempre y cuando ayude a que todos controlemos mejor el tema ;)

En cuanto a lo del println, al ejecutar los test Grails "wrapea" esa ejecución y los println no salen por consola, sino que los puedes ver en el informe que te generan en /target/test-reports/html donde tienes un enlace al System.out de cada test. Para mi gusto mucho mejor que dejarlos todos juntos en la consola, así ves directamente lo que saca el test que falla, por ejemplo.
Espero que te sirva, aunque igual ya lo conocías...
Kini, que estas de vacaciones déjalo ya no? jeje...se echa en falta un screen cast pronto...
Sigue así.
Abrazos