Envío/Recepción de mensajes y Tests...

4 views
Skip to first unread message

César Brea

unread,
Jul 17, 2009, 7:04:42 AM7/17/09
to tdde...@googlegroups.com
Hola a todos,

Voy a aprovechar éste, mi primer mensaje en la lista, para
comentaros/consultaros algo que llevo tiempo dándole vueltas y no
acabo de encontrar una solución que me convenza.

Se trata de cómo realizar tests (¿funcionales?) en desarrollos de
nodos de red. Es decir, orientado a eventos. Eventos que son
simplemente la recepción/envío de mensajes en un objeto.

Os pongo en un caso concreto y muy resumido:

* Tengo:
ObjetoCliente objCliente;
ObjetoServidor objServidor;

* Preparo un test:

void testEnvioRecepcionCliente(){

objCliente.enviarMensaje1();

Respuesta respuesta = objCliente.recibir();
assertEquals(respuesta, respuestaRecibida)
}


Con este simple test espero que entendáis mi problema. No puedo
llamar al método recibir(), sino que debería de alguna forma mi clase
test ser notificada cuando se reciba una nueva respuesta.

Por un lado, y como primera opción pensé en meter un Thread.sleep()
entre el envío y recepción. Pero claro, esto no es una solución para
nada válida ya que no puedes recibir más de una respuesta para cada
petición. Ni el test pasaría con varios clientes a la vez.

Otra opción es aplicar en esta clase el patrón obvervable y tener
un método update() donde actualizar el test consecuentemente. No se
hasta que punto esto sería un test válido ya que sólo podría tener un
test en esta clase.

Os cuento también la solución por la que he optado: Consiste en que
los clientes tengan un atributo donde almaceno un estado. Es decir,
lanzo las peticiones, espero un tiempo (Thread.sleep) y finalmente
consulto ese estado. Es similar a la primera de las aproximaciones
que usé, pero válido para probar varios clientes simultáneamente.


¿Alguno de vosotros está en desarrollos de este tipo y sabe cómo
usar de mejor forma los test?

Desde ya os agradezco cualquier comentario.

Un saludo,

César

José Manuel Beas

unread,
Jul 17, 2009, 9:49:26 PM7/17/09
to tdde...@googlegroups.com
¿Qué comportamiento quieres comprobar?

a) que ObjetoCliente sabe enviar mensajes
b) que ObjetoCliente sabe recibir mensajes
c) que ObjetoCliente sabe enviar y esperar la recepción de la
respuesta (de ObjetoServidor) al mensaje enviado

Sospecho que lo que quieres es la última, pero antes deberías tener
pruebas unitarias más sencillas (los casos a y b).

Luego puedes hacer una prueba donde integres ObjetoCliente y ObjetoServidor.

En los primeros dos casos puedes usar algún framework para "mockear"
ObjetoServidor y simular su existencia. Piensa también en si tu diseño
te permite inyectar ese doble (como un doble en las películas de
acción) porque si no es así deberías reconsiderar tu diseño para que
fuera más fácil de testear.

La idea es que primero te aseguras de los comportamientos de
ObjetoCliente (y de ObjetoServidor por otro lado, claro) y luego te
aseguras de que al "enchufarlos" funcionan juntos como se espera. Echa
un vistazo a esta categorización que creo que resume perfectamente lo
que quiero decir.
http://misko.hevery.com/2009/07/14/software-testing-categorization/

En el caso de la prueba de integración es perfectamente aceptable el
retardo (sleep) que pones antes de hacer el assert. El libro de
Koskela "Test Driven" lo recomienda (lo siento, no recuerdo la página)
y estoy casi seguro que el "xUnit Patterns" también.

Un saludo,
JMB
--
Un saludo,
Jose Manuel Beas

http://www.agile-spain.com
http://jmbeas.blogspot.com

Santiago L. Valdarrama

unread,
Jul 19, 2009, 1:03:41 AM7/19/09
to TDDev
La respuesta como bien te mencionaban es que debes utilizar alguna de
las bibliotecas existentes para generar mocks y poder probar tus
objetos.

La experiencia me ha demostrado que usando mocks se puede probar el
99.9% de los casos que se nos presentan a diario en la programación de
un sistema. Si no digo que es el 100% es para tratar de no ser
completamente absoluto.

Hay dos tipos de tests que puedes crear: el test unitario común
utilizando el mock para simular el envío de mensajes y probar el
comportamiento al recibir dichos mensajes, y un test de aceptación
donde realmente pruebes el escenario funcionando en un entorno real.
Ambos test deben estar separados ya que normalmente los test unitarios
deben correr de forma fácil sin dependencias con el entorno (y por
supuesto sin un Sleep que demore su ejecución).

Espero que te sirva de algo la ayuda.

Saludos,

Santiago Valdarrama
CEO - Laura Software
www.laurasoftware.com

On Jul 17, 9:49 pm, José Manuel Beas <jose.m.b...@gmail.com> wrote:
> ¿Qué comportamiento quieres comprobar?
>
> a) que ObjetoCliente sabe enviar mensajes
> b) que ObjetoCliente sabe recibir mensajes
> c) que ObjetoCliente sabe enviar y esperar la recepción de la
> respuesta (de ObjetoServidor) al mensaje enviado
>
> Sospecho que lo que quieres es la última, pero antes deberías tener
> pruebas unitarias más sencillas (los casos a y b).
>
> Luego puedes hacer una prueba donde integres ObjetoCliente y ObjetoServidor.
>
> En los primeros dos casos puedes usar algún framework para "mockear"
> ObjetoServidor y simular su existencia. Piensa también en si tu diseño
> te permite inyectar ese doble (como un doble en las películas de
> acción) porque si no es así deberías reconsiderar tu diseño para que
> fuera más fácil de testear.
>
> La idea es que primero te aseguras de los comportamientos de
> ObjetoCliente (y de ObjetoServidor por otro lado, claro) y luego te
> aseguras de que al "enchufarlos" funcionan juntos como se espera. Echa
> un vistazo a esta categorización que creo que resume perfectamente lo
> que quiero decir.http://misko.hevery.com/2009/07/14/software-testing-categorization/

José Manuel Beas

unread,
Jul 20, 2009, 6:18:47 AM7/20/09
to tdde...@googlegroups.com
Sí, pero mucho cuidado con el abuso de los mocks y con acoplar las pruebas a la implementación. Esto es algo que hemos discutido recientemente en el grupo local de Agile Spain en Madrid. :-)

Por último, lo que comenta Santiago de separar pruebas unitarias de pruebas de aceptación es algo que comenta también Misko Hevery en el enlace que adjunté el otro día.

Es importante que seas consciente de que cada tipo de prueba te irá dando un tipo de certeza diferente y que es el conjunto el que te da la "casi certeza" de que tu sistema es correcto y listo para ir a producción.
2009/7/19 Santiago L. Valdarrama <svp...@gmail.com>

Alfredo Casado

unread,
Jul 20, 2009, 9:23:54 AM7/20/09
to tdde...@googlegroups.com
Dejando de lado la separación de pruebas de unidad/funcionales, el problema es "¿como hacer pruebas funcionales con código asincrono en junit?"

En este blog dan algunas pautas: http://joe.truemesh.com/blog/000279.html

Otra opción es usar las clases Future y Callable de java.util.concurrent que precisamente sirven para automatizar la gestión de métodos que resuelven resultados de forma asincrona.

Echale un vistazo a estas cosas a ver si te sirven para tu problema, lo de esperar en un sleep en mi opinión es muy mala opción porque ralentizas si o si todos tus test, la ideal es:

- En cuanto se devuelva el resultado hacer el assert para ver que es correcto
- Tener un timeout y si se sobrepasa el timeout y no se ha devuelto nada considerar la prueba fallida.

De esta forma sitodo va bien no ralentizas N segundos por pueba tanto si va bien como si va mal.

César Brea

unread,
Jul 21, 2009, 3:19:42 AM7/21/09
to tdde...@googlegroups.com
Hola,

Antes de nada gracias por vuestras indicaciones y disculpad que haya
tardado en responder (llevo arrastrando el borrador varios días ;) ).

He estado pensando en la posibilidad de hacer test unitarios de
ambas clases: cliente y servidor. Tengo varias dudas...

* Ambas clases son independientes, es decir no se comunican
directamente llamando a sus métodos, sino que lo hacen a través de un
socket. ¿Cómo aplica en esto mi intención tener un mock de la clase
servidor? Es decir, ¿un mock no tiene funcionalidad, cómo "escucha" en
un puerto?

* De acuerdo en que para hacer un test unitario de la clase
cliente necesito un mock de la clase servidor. Pero... En el caso de
que la clase servidor sea un envoltorio de una librería de
envío/recepción de mensajes. Yo no debería hacer tests para esta
librería y por lo tanto, como no tengo nada que probar en servidor,
hacer directamente tests funcionales y no hacer unitarios. ¿Cómo véis
esto?


Alfredo, exactamente, ese es mi problema. Voy a echar un vistazo al
enlace y ya comento mis avances ( si los hay ;) ).

Muchas gracias a todos.

Saludos,

César




2009/7/20 José Manuel Beas <jose....@gmail.com>:

Carlos Ble

unread,
Jul 21, 2009, 3:39:20 AM7/21/09
to tdde...@googlegroups.com
Hola,

El 21 de julio de 2009 08:19, César Brea<dob...@gmail.com> escribió:
>
> Hola,
>
>  Antes de nada gracias por vuestras indicaciones y disculpad que haya
> tardado en responder (llevo arrastrando el borrador varios días ;) ).
>
>  He estado pensando en la posibilidad de hacer test unitarios de
> ambas clases: cliente y servidor. Tengo varias dudas...
>
>     *  Ambas clases son independientes, es decir no se comunican
> directamente llamando a sus métodos, sino que lo hacen a través de un
> socket. ¿Cómo aplica en esto mi intención tener un mock de la clase
> servidor? Es decir, ¿un mock no tiene funcionalidad, cómo "escucha" en
> un puerto?
>

Lo que tendras es un mock del socket entonces. El mock no se usa para
que funcione sino para que aisle lo que tu quieres probar y de manera
que cuando el mock interviene simplemente da una respuesta que tu le
has programado.
Pon que quieres probar cómo se comporta tu cliente cuando la
comunicacion es buena. Para ese caso te haces un mock del socket que
cuando se invoca devuelve un OK o lo que quiera que signifique que
todo fue bien.
Quédate con la idea de que los mocks no hacen nada, solo dan las
respuestas programadas que tu necesites para cada caso.


>     *  De acuerdo en que para hacer un test unitario de la clase
> cliente necesito un mock de la clase servidor.  Pero... En el caso de
> que la clase servidor sea un envoltorio de una librería de
> envío/recepción de mensajes.  Yo no debería hacer tests para esta
> librería y por lo tanto, como no tengo nada que probar en servidor,
> hacer directamente tests funcionales y no hacer unitarios. ¿Cómo véis
> esto?
>

Quizas te sea mas facil envolver el socket dentro de alguna clase que
implementa una interfaz que se dedica a las comunicaciones. Por
ejemplo, te creas algo como INetworkHandler con un método Send.
Internamente tu clase Send utilizará un socket pero cuando estás
diseñando el cliente, haces un mock de INetworkHandler para que dé la
respuesta que quieras. Desconozco si el socket que usas en java ya
implementa alguan interfaz que te puede servir de base para tu clase
de comunicaciones.
Los tests unitarios son la esencia, no te los saltes ;-)

José Manuel Beas

unread,
Jul 21, 2009, 12:55:58 PM7/21/09
to tdde...@googlegroups.com
+1 a Carlos


José Manuel Beas

unread,
Jul 21, 2009, 1:05:14 PM7/21/09
to tdde...@googlegroups.com


2009/7/20 Alfredo Casado <casado....@gmail.com>

Dejando de lado la separación de pruebas de unidad/funcionales, el problema es "¿como hacer pruebas funcionales con código asincrono en junit?"

En este blog dan algunas pautas: http://joe.truemesh.com/blog/000279.html

Otra opción es usar las clases Future y Callable de java.util.concurrent que precisamente sirven para automatizar la gestión de métodos que resuelven resultados de forma asincrona.

Echale un vistazo a estas cosas a ver si te sirven para tu problema, lo de esperar en un sleep en mi opinión es muy mala opción porque ralentizas si o si todos tus test, la ideal es:

- En cuanto se devuelva el resultado hacer el assert para ver que es correcto
- Tener un timeout y si se sobrepasa el timeout y no se ha devuelto nada considerar la prueba fallida.

De esta forma sitodo va bien no ralentizas N segundos por pueba tanto si va bien como si va mal.

Tienes razón, Alfredo, eso sería una mejora interesante si tienes que hacer muchas, muchas pruebas o si no tienes control sobre el parámetro que indica el timeout.

Se me ocurre la pregunta sobre cómo probar un sistema donde el timeout fuera de varios días. ;-)

Un saludo desde la playa,
JMB
Reply all
Reply to author
Forward
0 new messages