Pruebas de integración del envío de Email con el soporte de Spring.
0. Índice de contenidos.
- 1. Introducción.
- 2. Entorno.
- 3. Adaptando las librerías a la última versión de Spring.
- 4. Añadiendo aserciones al test con el soporte del servidor SMTP.
- 5. Haciendo uso del soporte de Spring para inyectar el servidor SMTP.
- 6. Referencias.
- 7. Conclusiones.
1. Introducción
Ya vimos hace algún tiempo las posibilidades que teníamos con el soporte de Spring de enviar emails simples, con attachments, basados en plantillas y con recursos en línea:
- Integración de Spring con el envío de emails.
- Integración de Spring con el envío de emails: técnicas avanzadas (I).
- Integración de Spring con el envío de emails: técnicas avanzadas (II)
En estos tutoriales se explican los pasos a dar para configurar el servicio y se realiza una prueba de envío a través de un test de junit. Si bien, dicho test no es tal,
puesto que carece de aserciones, el objetivo del mismo era el de levantar el contenedor de Spring y probar el envío efectivo a través de un servidor real, pero como
digo, la comprobación del resultado era manual y a posteriori de la ejecución del test.
Los test de integración son siempre los más complejos de testar puesto que emular el sistema de terceros con el que nos integramos en producción en
un entorno de pruebas no es trivial.
¿Alguien ha participado de un proyecto en el que haya comenzado a fallar la build porque en producción se ha modificado la password del servidor de correo?,
no hay que llegar a estos extremos, hacer un test de envío de mail que envíe un correo real no es de recibo.
Es aquí donde entra el objeto de este tutorial, realizar una prueba de concepto de un mock que emula un servidor de correo SMTP local.
Este tutorial también sería válido como complemento del de
envío de correo electrónico con el soporte de Jboss Seam, pero nos vamos a centrar en el soporte de Spring.
2. Entorno.
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 17′ (2.93 GHz Intel Core 2 Duo, 4GB DDR3 SDRAM).
- Sistema Operativo: Mac OS X Snow Leopard 10.6.1
- Spring 3.0.5.RELEASE
- Dumbster 1.6
3. Adaptando las librerías a la última versión de Spring.
Lo primero que hemos hecho es adaptar nuestras librerías a las últimas versiones e incluir la dependencia a librería
dumbster, que tiene el mock que nos interesa.
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.0.5.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>dumbster</groupId> <artifactId>dumbster</artifactId> <version>1.6</version> <scope>test</scope> </dependency>
El uso de dicha librería fue propuesto por Sam Brannen en el
#springio de este año,
como ejemplo de una buena práctica de test de integración, en su charla sobre
«Effective out-of-container Integration Testing»
4. Añadiendo aserciones al test con el soporte del servidor SMTP.
El código de nuestro test en relación con el envío del mail es el mismo, lo que difiere es la necesidad de arrancar y parar el servidor de SMTP y las
aserciones que podemos realizar con el soporte del mismo.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/applicationContext.xml" }) public class MailServiceTest { private static final Log log = LogFactory.getLog(MailServiceTest.class); private static final String EMAIL = "jmsanchez@autentia.com"; private static final String SUBJECT = "Entregable del #springio."; private static final String BODY = "Probando Fake SMTP Server en el envío de email con el soporte de Spring. By #autentia."; @Resource private MailService mailService; private SimpleSmtpServer server; @Before public void beforeTest(){ server = SimpleSmtpServer.start(2525); } @Test public void sendSimpleEmail() { mailService.send(EMAIL, SUBJECT, BODY); server.stop(); Assert.assertEquals("There must be a single email.",1,server.getReceivedEmailSize()); final Iterator<?> emailIter = server.getReceivedEmail(); final SmtpMessage email = (SmtpMessage)emailIter.next(); Assert.assertEquals(SUBJECT, email.getHeaderValue("Subject")); Assert.assertEquals(EMAIL, email.getHeaderValue("To")); Assert.assertTrue(email.getBody().contains("By #autentia.")); } }
Hemos añadido un método beforeTest para arrancar el servidor antes de la ejecución de cada test.
Después del envío del email, paramos el servidor y primero comprobamos que el número de emails recibidos en el mismo sea igual a uno.
Sabiendo que hay uno, lo obtenemos de la iteración y comprobamos su subject, el campo to y que contenga un texto predefinido en el body.
5. Haciendo uso del soporte de Spring para inyectar el servidor SMTP.
Para que funcione correctamente, hemos tenido que modificar el fichero de configuración de nuestra aplicación,
en el entorno de test, para que las propiedades del servidor del correo, sean
- mail.host=localhost
- mail.port=2525
Y mientras lo cambiaba, la inercia me ha llevado a replantearme la configuración puesto que estaba escribiendo en dos sitios distintos la misma cosa, la configuración
del puerto.
La solución pasa por publicar el servidor de SMTP en el contexto de Spring, como sigue:
<bean id="simpleSmtpServer" class="com.dumbster.smtp.SimpleSmtpServer" factory-method="start" scope="prototype"> <constructor-arg value="${mail.port}"/> </bean>
Con mail.port se inicializa tanto el servicio como el servidor, con lo que no me repito (DRY) y puedo inyectar ambos en cualquier punto manejado por el contenedor, incluso en los tests.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/applicationContext.xml" }) public class MailServiceTest { private static final Log log = LogFactory.getLog(MailServiceTest.class); private static final String EMAIL = "jmsanchez@autentia.com"; private static final String SUBJECT = "Entregable del #springio."; private static final String BODY = "Probando Fake SMTP Server en el envío de email con el soporte de Spring. By #autentia."; @Resource private MailService mailService; @Resource private SimpleSmtpServer server; @Test public void sendSimpleEmail() { mailService.send(EMAIL, SUBJECT, BODY); server.stop(); Assert.assertEquals("There must be a single email.",1,server.getReceivedEmailSize()); final Iterator<?> emailIter = server.getReceivedEmail(); final SmtpMessage email = (SmtpMessage)emailIter.next(); Assert.assertEquals(SUBJECT, email.getHeaderValue("Subject")); Assert.assertEquals(EMAIL, email.getHeaderValue("To")); Assert.assertTrue(email.getBody().contains("By #autentia.")); } }
El bean lo publicamos como prototype para que cada vez que se inyecte se cree una nueva instancia del mismo y se pueda parar el servidor en los tests sin problemas.
6. Referencias.
- http://quintanasoft.com/dumbster/
7. Conclusiones.
Desde la publicación de los tutoriales sobre envío de emails he recibido algún que otro mensaje de correo electrónico a mi buzón porque quien andaba probando el
código de los mismos no cambiaba mi dirección de email del campo to, espero que con este tutorial dejen de llegar 😉
Ahora en serio, me tomo este tutorial como un entregable después del #springio de este año.
Cuando te aportan tanto y de tanta calidad te sientes en deuda y quería realizar yo también una pequeña aportación a la comunidad.
Un saludo.
Jose
Más simple y claro imposible.
Está muy bien.