Diferencia entre revisiones de «Captura De Parametros»

De Dos Ideas.
Saltar a: navegación, buscar
(Captura de parámetro con Mockito)
Línea 108: Línea 108:
 
         replay(mockDao);
 
         replay(mockDao);
  
         InvasorDto resultado = planInvasionBo.findInvasorById(id);
+
         Invasor resultado = planInvasionBo.findInvasorMasPeligroso();
  
 
         verify(mockDao);
 
         verify(mockDao);
Línea 129: Línea 129:
 
Para realizar la captura de parámetros con Mockito podemos utilizar una funcionalidad que tiene que la denomina "Stubbing with callbacks".
 
Para realizar la captura de parámetros con Mockito podemos utilizar una funcionalidad que tiene que la denomina "Stubbing with callbacks".
 
Lo que hace es darnos la posibilidad de pasarle un callback a la llamada de un método maquetado.
 
Lo que hace es darnos la posibilidad de pasarle un callback a la llamada de un método maquetado.
En nuestro caso lo que haremos en ese callback es capturar el parámetro que recibe al ser llamado.
+
En nuestro caso lo que haremos en ese callback es capturar el parámetro que recibe al ser llamado. Los pasos son los siguientes:
 +
* Crear un atributo de la clase de Test que contendrá el parámetro capturado.
 +
* Crear un callback para el método a maquetar.
 +
* Capturar el parámetro en cuestión dentro del callback y asignarlo al atributo del Test.
 
<code java>
 
<code java>
 +
package test.com.dosideas.mock.business.impl;
 +
 +
//imports varios...
 +
import static org.mockito.Mockito.*;
 +
 +
public class PlanInvasionBoImplTest extends TestCase {
 +
 +
    private PlanInvasionBoImpl planInvasionBo;
 +
    @Mock private PlanInvasionDao daoMock;
 +
    private Filtro filtroCapturado;
 +
 +
    protected void setUp() throws Exception {
 +
        MockitoAnnotations.initMocks(this);
 +
        planInvasionBo = new PlanInvasionBoImpl();
 +
        planInvasionBo.setPlanInvasionDao(daoMock);
 +
 +
 +
    }
 +
 +
    public void testFindInvasorMasPeligroso() {
 +
 +
        Invasor invasor = new Invasor(id, "Zim");
 +
 +
        //crear el callback para el metodo findInvasorPorFiltro()
 +
        doAnswer(new Answer<Object>() {
 +
        stub(daoMock.findInvasorPorFiltro((Filtro)anyObject())
 +
          .toAnswer(new Answer<Filtro>() {
 +
          public Invasor answer(InvocationOnMock invocation) throws Throwable {
 +
            filtroCapturado = (Filtro)invocation.getArguments()[0];
 +
            return invasor;          }
 +
        });
 +
 +
        InvasorDto resultado = planInvasionBo.findInvasorById(id);
 +
 +
        // los assert tipicos
 +
 +
        // los assert sobre el Filtro capturado
 +
        assertNotNull(filtroCapturado);
 +
        assertTrue(filtroCapturado.getVelocidad() < VELOCIDAD_MAXIMA);
 +
        // El resto de los asserts necesarios sobre el filtro
  
 +
    }
 +
}
 
</code>
 
</code>
  
===Extensión del Matcher de Mockito===
 
 
(Agregar descripcion y codigo del Matcher capturador)
 
  
 
=Ver también=
 
=Ver también=

Revisión del 14:04 16 oct 2008

Hay situaciones en las que el estamos realizando un testeo con un Mock Object y queremos capturar un parámetro que recibe el mismo.

Esta situación suele producirse cuando hay un objeto que se crea dentro de los objetos que estamos probando y llega como parámetro a algún Mock Object. Hay unas cuantas condiciones que podemos pedir a EasyMock y Mockito que validen como parámetro esperado como por ejemplo igualdad, expresiones regulares, no nulo, nulo, algunas comprobaciones con Strings y primitivos, etc. Pero incluso a veces esto no alcanza. El objeto fue creado dentro de otro objeto, es decir que no podemos ni inyectarlo desde fuera ni conseguirlo por medios naturales y queremos inspeccionar sus atributos y realizar una serie de asserts. Es ahí cuando conseguir una referencia al mismo nos resulta ütil.

Ejemplo

El escenario

Supongamos la siguiente interfaz de negocio:

public interface PlanInvasionBo {
    public InvasorDto findInvasorMasPeligroso();
}

... la siguiente interfaz de DAO

public interface PlanInvasionDao {
    public Invasor findInvasorPorFiltro(Filtro filtro);
}

... y el siguiente filtro

public class Filtro {
    private Fuerza fuerza;
    private Velocidad velocidad;
    private Destreza destreza;
    // sus metodos accesores
}

Dentro de la implementación de la clase PlanInvasionBo se crea una instancia de Filtro que se utiliza para comunicarse con el DAO pero no es externalizada en ningún momento (salvo como parámetro en la llamada al método del DAO) ni existe la posiblidad de inyectarla desde fuera.

public class PlanInvasorBoImpl implements PlanInvasor {
    private PlanInvasionDao planInvasionDao;
    // otros atributos
    
    public Invasor findInvasorMasPeligroso() {
        // Realiza ciertos guarismos internos 
        // para determinar la Fuerza, Velocidad y Destreza
        Fuerza fuerza = calcularFuerza();
        Velocidad velocidad = calcularVelocidad();
        Destreza destreza = calcularDestreza();
        // Utiliza los valores determinados para construir un Filtro
        Filtro filtro = new Filtro(fuerza, velocidad, destreza);
        // Llama al DAO con el filtro construido internamente
        return planInvasionDao.findInvasorPorFiltro(filtro);
    }
    // otros metodos
}

El objetivo

El objetivo que nos planteamos es poder inspeccionar en un test que los valores del objeto Velocidad estén dentro de ciertos límites.

El problema

El problema que tenemos es que el objeto Velocidad se crea a partir de unos métodos privados de PlanInvasionBo y está dentro de otro objeto que se crea también dentro de PlanInvasionBo al que tampoco tenemos acceso. La única comunicación de este objeto con el exterior es en forma de parámetro a través de la llamada al método del DAO.

Una posible solución

Una posible solución a nuestro objetivo es capturar el parámetro Filtro que recibe el método del DAO que en el caso del test será un Mock Object.

Captura de parámetro con EasyMock

Para capturar un parámetro con EasyMock tenemos que:

  • Crear un objeto Capture parametrizado con la clase que va a capturar.
  • En el expect del método que recibe el parámetro a capturar se utiliza el método estático EasyMock.capture que recibe al capturador.
  • Pedirle al capturador el valor capturado.

package test.com.dosideas.mock.business.impl;
//imports varios...
import static org.easymock.EasyMock.*;
public class PlanInvasionBoImplTest extends TestCase {
    private PlanInvasionBoImpl planInvasionBo;
    private PlanInvasionDao daoMock;
    protected void setUp() throws Exception {
        daoMock = createMock(PlanInvasionDao.class);
        planInvasionBo = new PlanInvasionBoImpl();
        planInvasionBo.setPlanInvasionDao(daoMock);
    }
    public void testFindInvasorMasPeligroso() {
        Invasor invasor = new Invasor(id, "Zim");
        // Crear un Capture para utilizar en la maquetacion del metodo
        Capture<Filtro> caturaFiltro = new Capture<Filtro>();
        expect(mockDao.findInvasorPorFilro(capture(capturaFiltro)).andReturn(invasor);
        replay(mockDao);
        Invasor resultado = planInvasionBo.findInvasorMasPeligroso();
        verify(mockDao);
        // los assert tipicos
        
        // Conseguir la referencia al filtro que llego como parametro
        // al metodo del daoMock
        Filtro filtro = capturaFiltro.getValue();
        assertNotNull(filtro);
        assertTrue(filtro.getVelocidad() < VELOCIDAD_MAXIMA);
        // El resto de los asserts necesarios sobre el filtro
    }
}

Captura de parámetro con Mockito

Para realizar la captura de parámetros con Mockito podemos utilizar una funcionalidad que tiene que la denomina "Stubbing with callbacks". Lo que hace es darnos la posibilidad de pasarle un callback a la llamada de un método maquetado. En nuestro caso lo que haremos en ese callback es capturar el parámetro que recibe al ser llamado. Los pasos son los siguientes:

  • Crear un atributo de la clase de Test que contendrá el parámetro capturado.
  • Crear un callback para el método a maquetar.
  • Capturar el parámetro en cuestión dentro del callback y asignarlo al atributo del Test.

package test.com.dosideas.mock.business.impl;
//imports varios...
import static org.mockito.Mockito.*;
public class PlanInvasionBoImplTest extends TestCase {
    private PlanInvasionBoImpl planInvasionBo;
    @Mock private PlanInvasionDao daoMock;
    private Filtro filtroCapturado;
    protected void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        planInvasionBo = new PlanInvasionBoImpl();
        planInvasionBo.setPlanInvasionDao(daoMock);


    }
    public void testFindInvasorMasPeligroso() {
        Invasor invasor = new Invasor(id, "Zim");
        //crear el callback para el metodo findInvasorPorFiltro()
        doAnswer(new Answer<Object>() {
        stub(daoMock.findInvasorPorFiltro((Filtro)anyObject())
          .toAnswer(new Answer<Filtro>() {
          public Invasor answer(InvocationOnMock invocation) throws Throwable {
            filtroCapturado = (Filtro)invocation.getArguments()[0];
            return invasor;           }
        });
        InvasorDto resultado = planInvasionBo.findInvasorById(id);
        // los assert tipicos
        // los assert sobre el Filtro capturado
        assertNotNull(filtroCapturado);
        assertTrue(filtroCapturado.getVelocidad() < VELOCIDAD_MAXIMA);
        // El resto de los asserts necesarios sobre el filtro
    }
}


Ver también