Testear sin resultado esperado.

26 views
Skip to first unread message

Pablo Braulio

unread,
Jul 10, 2014, 3:10:03 AM7/10/14
to Lista tdd
Hola a todos.

Quería plantear una duda sobre si tiene sentido testear determinada situación.

El contexto es el siguiente:

Tengo una ClaseA, que tiene una dependencia de la ClaseB.
La ClaseB, tiene un método "persist" (al que llamo en la claseA), que maneja la persistencia con la BD, pero no devuelve nada.

En este caso, si testeo la ClaseA no voy a esperar ningún resultado, pues esta sólo llama al método "persist" de la ClaseB. Es decir, que el test tan sólo tendría Mocks sobre la ClaseB y su método.

Según veo, al hacer el Mock de la ClaseB, este me comprueba que dicha clase exista. Por lo que si la elimino o cambio de nombre el test me lo detectará. Pero si elimino o cambio de nombre el método "persist", el mock ni se entera.

¿Creéis que tiene sentido hacer un test de este tipo sin hacer ningún Assert, pues no devuelve ningún resultado?.


Espero haberme explicado, bien. De lo contrario pondré un código de ejemplo.

Saludos cordiales.
Pablo.

Si lo reenvías, ten la precaución de borrar los datos de procedencia que
encabezarían tu reenvío – empezando por mi dirección de correo
electrónico - . Coloca siempre las direcciones de tus contactos en el
campo <CCO> para que viajen discretas, no en el campo <Para> ni en
el<CC>. De esa forma nadie que lo reciba tendrá constancia de las señas
de los demás destinatarios a los que también se remite. Todo ello a fin
de evitar que nadie se aproveche de todas las direcciones que se van
acumulando al pasar de buzón a buzón para el lanzamiento de correo
basura y otras indeseadas lindezas. Aparte claro está de garantizar la
privacidad.



Enviado con MailTrack

Vicenç Garcia

unread,
Jul 10, 2014, 4:30:52 AM7/10/14
to tdde...@googlegroups.com
Hola Pablo,

pues supongo que los detalles dependeran del lenguaje en el que trabajes, pero en general se puede hacer un verify de una funcion en concreto, con lo que si le cambias el nombre el test te va a cantar. Esa clase/metodo no hace nada mas? Es simplemente un pass-through?

Un saludo,
Vicenç


--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a tddev-sp+u...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/tddev-sp.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--

Vicent Soria

unread,
Jul 10, 2014, 4:31:26 AM7/10/14
to tdde...@googlegroups.com
Hola Pablo,

Lo que tendrías que comprobar es que la ClaseA llama al método "persist" de la ClaseB, es decir en tu test, comprobarás que el método "persist" de la ClaseB ha sido llamado (ya sea diciéndole los parámetros que espera, o solo que ha sido llamado).

No haces un assert explícito, pero la librería de mocks hace uno internamente, así que el assert, lo tienes.

Si en tu código no llamas al método "persist" de la ClaseB, petará el test.



--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a tddev-sp+u...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/tddev-sp.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
Vicent Soria

Pablo Braulio

unread,
Jul 10, 2014, 4:32:33 AM7/10/14
to Lista tdd
Trabajo con PHP. Testeo con PHPUnit y Mockery.

No he visto nada de Verify, pero miraré a ver si hay algo.



Enviado con MailTrack

Saludos cordiales.
Pablo.

Si lo reenvías, ten la precaución de borrar los datos de procedencia que
encabezarían tu reenvío – empezando por mi dirección de correo
electrónico - . Coloca siempre las direcciones de tus contactos en el
campo <CCO> para que viajen discretas, no en el campo <Para> ni en
el<CC>. De esa forma nadie que lo reciba tendrá constancia de las señas
de los demás destinatarios a los que también se remite. Todo ello a fin
de evitar que nadie se aproveche de todas las direcciones que se van
acumulando al pasar de buzón a buzón para el lanzamiento de correo
basura y otras indeseadas lindezas. Aparte claro está de garantizar la
privacidad.


Vicenç Garcia

unread,
Jul 10, 2014, 4:36:36 AM7/10/14
to tdde...@googlegroups.com
Con mockery creo que te tienes que mirar la funcion shouldReceive

Pablo Braulio

unread,
Jul 10, 2014, 4:38:20 AM7/10/14
to Lista tdd
Si, esa función es la que estoy usando, pero el caso es que si mi claseA no llamo al método "persist", el test falla. Esto es correcto.

Pero si en mi claseB cambio el nombre al método "persist" o lo elimino, el mock no lo detecta y lo da por válido.:-(



Enviado con MailTrack

Saludos cordiales.
Pablo.

Si lo reenvías, ten la precaución de borrar los datos de procedencia que
encabezarían tu reenvío – empezando por mi dirección de correo
electrónico - . Coloca siempre las direcciones de tus contactos en el
campo <CCO> para que viajen discretas, no en el campo <Para> ni en
el<CC>. De esa forma nadie que lo reciba tendrá constancia de las señas
de los demás destinatarios a los que también se remite. Todo ello a fin
de evitar que nadie se aproveche de todas las direcciones que se van
acumulando al pasar de buzón a buzón para el lanzamiento de correo
basura y otras indeseadas lindezas. Aparte claro está de garantizar la
privacidad.


Iñaki Garcia

unread,
Jul 10, 2014, 4:38:55 AM7/10/14
to tdde...@googlegroups.com

No se si phpunit pero en phake hay funcionalidad verify. Algun php-ero seguro que lo sabe

Vicenç Garcia

unread,
Jul 10, 2014, 4:49:17 AM7/10/14
to tdde...@googlegroups.com
Creo que el valor por defecto es zeroOrMoreTimes. Tendrias que utilizar algo de este estilo:

$mockeryMock->shouldReceive('someMethod')->times(3);

Pero bueno, tengo poca idea de PHP y Mockery, que conste :P

Antonio Martinez

unread,
Jul 10, 2014, 4:56:50 AM7/10/14
to tdde...@googlegroups.com
Desde mi poca experiencia con test y TDD.  En .NET

1. Tengo alguno tests que no tienen asserts, porque o simplemente verifican que todo el proceso se realice correctamente o comprueban que se lanza una excepción concreta.
2. Si haces un mock de la clase que llama a persist y a su vez de la función persist, es porque no es relevante la función ni su resultado. En principio persist debe estar en una interfaz cuyo nombre no debe cambiar por motivos de compatibilidad. Si el nombre de tu función puede cambiar (porque no dependa de ti o sea una api de terceros) haz un facade o adapter para evitar que afecte a tu código o a tus tests.

Espero ayudar y no meter mucho la pata.

Vicent Soria

unread,
Jul 10, 2014, 5:01:03 AM7/10/14
to tdde...@googlegroups.com
Pablo, te falta añadir esto al tearDown():

Mockery::close();

Si no lo pones, no hace los asserts.

También puedes añadir lo siguiente al phpunit.xml de manera global:

    <listeners>
        <listener class="\Mockery\Adapter\Phpunit\TestListener" />
    </listeners>

Saludos.



--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a tddev-sp+u...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/tddev-sp.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
Vicent Soria

Luis

unread,
Jul 10, 2014, 5:17:31 AM7/10/14
to tdde...@googlegroups.com
No se ahora mismo si en PHPUnit hay espías, pero debería ser con uno de esos.
Luis Sánchez Castellanos

Yo nunca huyo, doy media vuelta y sigo avanzando..

Pablo Braulio

unread,
Jul 10, 2014, 5:36:18 AM7/10/14
to Lista tdd
Perfecto.

Gracias a todos por los comentarios.



Enviado con MailTrack

Saludos cordiales.
Pablo.

Si lo reenvías, ten la precaución de borrar los datos de procedencia que
encabezarían tu reenvío – empezando por mi dirección de correo
electrónico - . Coloca siempre las direcciones de tus contactos en el
campo <CCO> para que viajen discretas, no en el campo <Para> ni en
el<CC>. De esa forma nadie que lo reciba tendrá constancia de las señas
de los demás destinatarios a los que también se remite. Todo ello a fin
de evitar que nadie se aproveche de todas las direcciones que se van
acumulando al pasar de buzón a buzón para el lanzamiento de correo
basura y otras indeseadas lindezas. Aparte claro está de garantizar la
privacidad.


Angel Java Lopez

unread,
Jul 10, 2014, 5:41:49 AM7/10/14
to tdde...@googlegroups.com
Hola gente!

Yo para este tipo de casos, prefiero otro camino. 

En primer lugar, no se cuando aparecio la clase B, en que test. Pero en mi flujo de trabajo, cuando aparece, la implemento, como una clase del sistema, no un mock, pero sin DB. Por ejemplo, guardando los datos en memoria. Y asi la entrego el viernes, al final de la iteracion. Y para ver que persistio, se implementa un metodo de recuperar, por ejemplo, por id, contra esa clase B que implementa todo en memoria.

Asi voy por varios tests y hasta iteraciones. Solo cuando realmente me aparezca el caso de uso "necesito MAS persistencia", implemento B2, quizas contra una base de datos relacional, o quizas en archivos formato JSON o quizas MongoDB. Siempre tratando de ir por el camino mas simple, siguiendo el flujo de TDD. Se podria considerar un caso de refactor. La API y la interaccion con el sistema en construccion no cambia. En vez de A llamar a B1 (la en memoria original), en algunos test pasa a llamar a B2 (incluso duplico los tests, no borro los de A llamando a B1, esto me permite detectar fallos de logica en refactor u otras cosas en A, sin tener que revisar tambien si el fallo no esta basado en B2. Si un test falla con A+B1, y con A+B2, el problema huele a que esta en A). Poco a poco, todos los test A+B1 tienen su correlato en A+B2.

Luego analizo si los test A+B2 (los que usan una base de datos) son MUY MUY lentos o no. Con el hardware de desarrollo actual, y con la posibilidad de usar base de datos en memoria, no parece mucho que es el caso. Prefiero tener A+B1, que permitio desarrolla y probar A de forma independiente de la persistencia, y A+B2 que me asegura que el caso de persistencia funciona, que tener mocks. Luego refactorear B2 a que use la base de datos final, o crear B3. Pero en general, me basta con ir refactoreando B2 para pasar, digamos, de archivos JSON, o MongoDB, a una base de datos relacional si es necesario. Pero si A+B2 fueran MUY MUY lentos, los correria en la integracion continua al menos.

Pero reconozco que este camino no es muy popular. Veo que muchos equipos comienzan con base de datos desde la primera iteracion. Yo no lo he visto necesario, y seguir primero por el camino en memoria me ha dado excelentes resultados, mucha agilidad en los cambios, aprehension real de los casos de uso ANTES de implementar una base de datos, etc...

Si de casualidad me toca un equipo que quiere base de datos desde el principio, trato de ir realmente con test contra la base de datos. Sino, existe la tendencia de poner mocks que luego uno no esta seguro de si el sistema funciona o no. He visto sistemas con gran cobertura de codigo, grandes tests, todo en verde, y que a los dos clicks fallan en cuatro continentes, porque de tanto mock nunca se llega a llamar a tal procedimiento almacenado que funciona mal.

Nos leemos!

Angel "Java" Lopez
@ajlopez

Pablo Braulio

unread,
Jul 10, 2014, 6:23:15 AM7/10/14
to Lista tdd
Lo de los listeners de Mockery, un detalle. Funciona perfecto.

Muchas gracias Viçent.



Enviado con MailTrack

Saludos cordiales.
Pablo.

Si lo reenvías, ten la precaución de borrar los datos de procedencia que
encabezarían tu reenvío – empezando por mi dirección de correo
electrónico - . Coloca siempre las direcciones de tus contactos en el
campo <CCO> para que viajen discretas, no en el campo <Para> ni en
el<CC>. De esa forma nadie que lo reciba tendrá constancia de las señas
de los demás destinatarios a los que también se remite. Todo ello a fin
de evitar que nadie se aproveche de todas las direcciones que se van
acumulando al pasar de buzón a buzón para el lanzamiento de correo
basura y otras indeseadas lindezas. Aparte claro está de garantizar la
privacidad.


Pablo Braulio

unread,
Jul 10, 2014, 6:30:14 AM7/10/14
to Lista tdd
Hola Angel.

Creo que mi duda no iba por donde lo planteas tu.
Realmente yo no quiero testear la persistencia de datos, sino mas bien testear dependencias en una clase que no tiene ninguna lógica implementada. Es decir, en el caso que planteo, la ClaseA, tan sólo pasa datos a la ClaseB.
Mi duda era que si tenía sentido hacer ese test a la ClaseA, para sólo "testear" que se están resolviendo las dependencias que tiene ya que no hay comportamiento esperado.
Tenía la duda, pues tal como estaba usando el mock, sólo me detectaba el fallo si la ClaseB no existía o era renombrada. No validaba sus cambios internos, como el renombrado o eliminación de métodos usados.
Con los listener que me ha dicho Viçent Soria, me lo hace correctamente.

Gracias por tu comentario.



Enviado con MailTrack

Saludos cordiales.
Pablo.

Si lo reenvías, ten la precaución de borrar los datos de procedencia que
encabezarían tu reenvío – empezando por mi dirección de correo
electrónico - . Coloca siempre las direcciones de tus contactos en el
campo <CCO> para que viajen discretas, no en el campo <Para> ni en
el<CC>. De esa forma nadie que lo reciba tendrá constancia de las señas
de los demás destinatarios a los que también se remite. Todo ello a fin
de evitar que nadie se aproveche de todas las direcciones que se van
acumulando al pasar de buzón a buzón para el lanzamiento de correo
basura y otras indeseadas lindezas. Aparte claro está de garantizar la
privacidad.


El 10 de julio de 2014, 11:41, Angel Java Lopez <ajlop...@gmail.com> escribió:

daniel....@freelancemadrid.es

unread,
Jul 23, 2014, 5:59:26 AM7/23/14
to tdde...@googlegroups.com
2014-07-10 10:48 GMT+02:00 Vicenç Garcia <vincen...@gmail.com>:
Creo que el valor por defecto es zeroOrMoreTimes. Tendrias que utilizar algo de este estilo:

$mockeryMock->shouldReceive('someMethod')->times(3);

Pero bueno, tengo poca idea de PHP y Mockery, que conste :P



Hola Braulio.

Ya te han contestado, como se hace con Mockery, asi que voy a completar en como se hace con PHPUnit, la otra librería que usas.


        // Create a stub for the SomeClass class.
        $stub = $this->getMock('SomeClass');

        // Configure the stub.
        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnValue('foo'));

Por si no se entiende bien, el $this->any() es 0 o más veces, en tu caso, tendrías que pasarle $this->once(). Puedes completar la info aqui[1].


--
-------------------------------------------------------------------------------------
Daniel González Cerviño
Developer http://desarrolla2.com
Tel (+34) 653 96 50 48
Mail daniel....@freelancemadrid.es
Twiter: http://twitter.com/desarrolla2
Linkedin: http://www.linkedin.com/in/desarrolla2
Github: https://github.com/desarrolla2
-------------------------------------------------------------------------------------
Reply all
Reply to author
Forward
0 new messages