TDD y expresiones lambda

37 views
Skip to first unread message

Juan Barrionuevo

unread,
Apr 23, 2013, 11:02:22 PM4/23/13
to tddev-sp
Estoy queriendo crear un test sobre una expresión lambda. Más específicamente, sobre entity framework.

Tengo una clase que oficia de repositorio y la misma posee un método recibe el id de un cliente y devuelve el objeto cliente encontrado que posea ese id.
Esta es la clase:

public class RepositorioClientes
{
    private readonly IContexto contexto;

    public RepositorioClientes( IContexto contexto )
    {
        this.contexto = contexto;
    }

    public Cliente ObtenerPorId( int idBuscado )
    {
        return this.contexto.Clientes.Where( x => x.Id == idBuscado ).FirstOrDefault();
    }
}

Lo que no me convence de mi test, es que yo puedo cambiar la expresión lambda (extendiéndola) y el test seguiría dando verde porque no valido que la expresión que se ejecuta es:
x => x.Id == variable

[TestMethod]
public void ObtenerPorIdTest()
{
    int idBuscado = 123;
    List<Cliente> stubClientes = new List<Cliente>();
    stubClientes.Add( new Cliente() { Id = 123 } );
    IDbSet<Cliente> mockClientes = MockRepository.GenerateStrictMock<IDbSet<Cliente>>();
    mockClientes.Expect( m => m.Provider ).Repeat.Once().Return( stubClientes.AsQueryable().Provider );
    mockClientes.Expect( m => m.Expression ).Repeat.Once().Return( stubClientes.AsQueryable().Expression );
    IContexto mockContexto = MockRepository.GenerateStrictMock<IContexto>();
    mockContexto.Expect( m => m.Clientes ).Repeat.Once().Return( mockClientes );
    RepositorioClientes repositorio = new RepositorioClientes( mockContexto );

    Clienteactual = repositorio.ObtenerPorId( idBuscado );

    Assert.AreEqual( 123, actual.Id );
    mockContexto.VerifyAllExpectations();
}

Espero haber sido claro en mi duda.
Desde ya, muchas gracias.


--
Juan J. Barrionuevo

Programación SOLIDa

JJG

unread,
Apr 24, 2013, 2:20:08 AM4/24/13
to tdde...@googlegroups.com
Juan no soy muy experto ni en IRepository ni en lambas, así que disculpa si lo que digo es una tontería.

Tal vez no tenga mucho sentido centrarte en verificar la función lamba per sé, sino verificar si, bajo distintos conjuntos de valores, el método ObtenerPorId devuelve el resultado esperado. si es así puedes asumir que la función lambda funciona correctamente, ya que lo único que hace tu método es, precisamente ejecutar esa función lamba (el resto son funciones de librería que asumimos que son correctas).

Un saludo.

Vicenç Garcia

unread,
Apr 24, 2013, 2:28:07 AM4/24/13
to tdde...@googlegroups.com
exacto, yo aquí me crearía unos tests de integración que hacen las verificaciones que necesites. 


2013/4/24 JJG <jjgrod...@gmail.com>

--
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 correos electrónicos, envía un correo electrónico a tddev-sp+u...@googlegroups.com.
Para publicar una entrada en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/tddev-sp?hl=es.
Para obtener más opciones, visita https://groups.google.com/groups/opt_out.
 
 



--

Diego Güemes

unread,
Apr 24, 2013, 3:19:46 AM4/24/13
to tdde...@googlegroups.com
Creo que la capa de tests que estás metiendo es "innecesaria". Evidentemente, el contexto de Entity Framework funciona (o debería funcionar), por lo que no haría verificaciones sobre las llamadas que se realizan. Como te han comentado por aquí arriba, lo más adecuado parece crear tests de integración, en tu caso concreto, que por ejemplo un ID inexistente devuelve nulo o una excepción y que tras haber insertado un elemento, puede recuperarlo a través de este método.

Un saludo,
Diego

JJG

unread,
Apr 24, 2013, 5:05:36 AM4/24/13
to tdde...@googlegroups.com
Diego, tu respuesta es muy interesante.

En el caso concreto de Juan yo le animo a que defina los caso de prueba con los que él se sienta cómodo y seguro, y ya se dará cuenta él mismo de si, más adelante, puede quitarlos.

Eso sí, añadir un caso de prueba es como tener un hijo, implica la responsabilidad de mantenerlo y atenderlo ;)

Un saludo.

Angel Java Lopez

unread,
Apr 24, 2013, 5:38:18 AM4/24/13
to tdde...@googlegroups.com
Hola gente!

Juan... hmmm... cuando tengo un proyecto asi, lo que hago es directamente probar contra una base de datos conocida (con estado conocido), y en cada test pongo transaccion sin confirmarla. Prueba que dado un Id, me devuelva el registro que espero, que dado otro Id que no existe, me devuelva null, y asi. En tu test, entonces en mi caso no usaria ningun mock (practicamente casi no uso mocks, en ya decenas de proyectos).

Mas particular mio, durante las primeras semanas de desarrollo, no uso base de datos, asi que cuando llego a tu caso, cambio la implementacion de dominio en memoria por un dominio en base de datos, y uso los mismos tests que antes: hay pocos tests nuevos, solo que los corro dos veces: contra una implementacion en memoria (o lo que sea) y luego contra una implementacion sobre la base de datos. Pero esto es una particularidad mia, a discutir.

Para mi es un test mas: la T de TDD es de test, no me importa de que tipo, siempre y cuando no vaya en contra del flujo de trabajo (tarde 10 minutos para correr, haya que hacer 10 comandos para preparar todo antes de correrlo, etc).

Nos leemos!

Angel "Java" Lopez
@ajlopez



2013/4/24 Juan Barrionuevo <intre...@gmail.com>

--

Alfredo Casado

unread,
Apr 24, 2013, 6:09:38 AM4/24/13
to tdde...@googlegroups.com
Una recomendación general cuando se usen mocks: Nunca mockear una clase que no es tuya, un artículo sobre el tema que no esta mal: http://davesquared.net/2011/04/dont-mock-types-you-dont-own.html

Como lo que estas implementando es un repositorio, esta es la clase que te abstrae de la persistencia, cuando pruebes tus clases de negocio tendrá todo el sentido del mundo mockear este repositorio. Pero cuando pruebas el repositorio preguntate ¿que quiero probar?, ¿que quiero descubrir con este test?:
  - que llamo a los métodos correctos y en el orden correcto a la librería de acceso a bd que uso (eso es lo que pruebas con mocks)
  - que funcionan las clases que me integran con la base de datos.


Victor Paredes

unread,
Apr 24, 2013, 8:09:31 AM4/24/13
to tdde...@googlegroups.com
Por lo que veo en el ejemplo ( y en mi humilde opinion ) el problema me suena un poco mas semantico que de concepto.
 
La clase repositorio es un componente que esta destinado a funcionar siempre con Entity Framework, ya que al cambiar la inyeccion lo unico que cambiamos es un context por otro, seria imposible que el mismo repositorio funcionara con Hibernate. El test prueba la logica del repositorio inyectandole el contexto para evitar ir contra la base de datos fisica y no tener un test que dependa de otro componente.
 
Con el conocimiento de TDD que tengo me surgen dos conclusiones:
 
Si tu capa de datos no tiene ninguna validacion extra yo cambiaria el nombre del "Repositorio" a "RepositorioEntityFramework", mas adelante si existiera otro motor de persistencia de datos haria una nueva clase llamada "RepositorioHibernate" que implemente la misma interface que la anterior y luego el que las consuma que decida cual usar.
 
Por otro lado, si tu capa de negocio tiene alguna validacion extra ( cualquiera que fuera siempre que pertenesca a esta capa ) le haria un "wrapper" a la clase que inyectas, de esta forma tenes una clase sin test que encapsula al acceso real a los datos y una clase repositorio generica con los test de los casos que necesitas probar.
 
Esto es una opinion formada con el conocimiento que tengo de TDD, si alguien le ve algun error o alguna contra aviseme asi aprendo un poco mas :D
Reply all
Reply to author
Forward
0 new messages