Captura De Parametros
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.
Contenido
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);
InvasorDto resultado = planInvasionBo.findInvasorById(id);
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.
Extensión del Matcher de Mockito
(Agregar descripcion y codigo del Matcher capturador)