2009-07-17 17 views
181

Tengo una llamada al método que quiero simular con mockito. Para empezar, he creado e inyectado una instancia de un objeto sobre el que se llamará el método. Mi objetivo es verificar uno de los objetos en la llamada al método.Verificar el valor del atributo del objeto con mockito

¿Existe alguna forma de que el mockito le permita afirmar o verificar el objeto y sus atributos cuando se llama al método de prueba?

ejemplo

Mockito.verify(mockedObject) 
     .someMethodOnMockedObject(
       Mockito.<SomeObjectAsArgument>anyObject()) 

En vez de hacer anyObject() Quiero ver ese objeto argumento contiene algunos campos particulares

Mockito.verify(mockedObject) 
     .someMethodOnMockedObject(
       Mockito.<SomeObjectAsArgument>**compareWithThisObject()**) 

Respuesta

383

Nueva característica añadida a Mockito hace aún más fácil,

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class); 
verify(mock).doSomething(argument.capture()); 
assertEquals("John", argument.getValue().getName()); 

Tome un vistazo a Mockito documentation

+0

si su método tiene más de un argumento, debe usar Matchers para todos los demás argumentos también. https://akcasoy.wordpress.com/tag/argumentcaptor/ – robsonrosa

+1

¿Qué pasa si hay múltiples argumentos? ¿Cómo especifica el exacto en el que está interesado? –

+2

@IgorGanapolsky Suponiendo un segundo parámetro de cadena para hacer algo que necesita hacer: verificar (simular) .doAlgo (argument.capture(), anyString()); – GreenTurtle

39

una posibilidad más, si no desea utilizar ArgumentCaptor (por ejemplo, porque se También estoy usando el stubbing), es usar Hamcrest Matchers en combinación con Mockito.

import org.mockito.Mockito 
import org.hamcrest.Matchers 
... 

Mockito.verify(mockedObject).someMethodOnMockedObject(Mockito.argThat(
    Matchers.<SomeObjectAsArgument>hasProperty("propertyName", desiredValue))); 
+0

Nota: asegúrese de que el paquete 'Matchers' es correcto, ya que escribir la misma línea de código con la clase' org.mockito.Matchers' arroja una excepción engañosa que indica que el parámetro de la función simulada simplemente no coincide. – buer

34

creo que la forma más fácil de verificar un objeto argumento es utilizar el método de refEq:

Mockito.verify(mockedObject).someMethodOnMockedObject(Matchers.refEq(objectToCompareWith)); 

Se puede utilizar incluso si el objeto no implementa equals(), ya que se utiliza la reflexión. Si no desea comparar algunos campos, solo agregue sus nombres como argumentos para refEq.

+0

Esto prueba la igualdad de referencia (el mismo objeto no 'igual'). –

+2

@ Adam Arold No, "ref" no significa referencia, significa reflexión. Ver el código fuente en 'org.mockito.Matchers'. – John29

+0

No cambia el hecho de que no está funcionando. Lo intenté. –

9

Esta es la respuesta basada en answer from iraSenthil pero con anotación (Captor). En mi opinión tiene algunas ventajas:

  • Es más corto
  • que es más fácil de leer
  • Puede manejar los genéricos sin advertencias

Ejemplo:

@RunWith(MockitoJUnitRunner.class) 
public class SomeTest{ 

    @Captor 
    private ArgumentCaptor<List<SomeType>> captor; 

    //... 

    @Test 
    public void shouldTestArgsVals() { 
     //... 
     verify(mockedObject).someMethodOnMockedObject(captor.capture()); 

     assertThat(captor.getValue().getXXX(), is("expected")); 
    } 
} 
+0

El enlace "Captor" está roto – Thermech

+1

@Thermech thx, está corregido ahora :) –

+0

Esto solo funcionará para un solo argumento en params. –

4

Si' Usando Java 8, puede usar expresiones Lambda para hacer coincidir.

import java.util.Optional; 
import java.util.function.Predicate; 

import org.hamcrest.BaseMatcher; 
import org.hamcrest.Description; 

public class LambdaMatcher<T> extends BaseMatcher<T> 
{ 
    private final Predicate<T> matcher; 
    private final Optional<String> description; 

    public LambdaMatcher(Predicate<T> matcher) 
    { 
     this(matcher, null); 
    } 

    public LambdaMatcher(Predicate<T> matcher, String description) 
    { 
     this.matcher = matcher; 
     this.description = Optional.ofNullable(description); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public boolean matches(Object argument) 
    { 
     return matcher.test((T) argument); 
    } 

    @Override 
    public void describeTo(Description description) 
    { 
     this.description.ifPresent(description::appendText); 
    } 
} 

Ejemplo llamada

@Test 
public void canFindEmployee() 
{ 
    Employee employee = new Employee("John"); 
    company.addEmployee(employee); 

    verify(mockedDal).registerEmployee(argThat(new LambdaMatcher<>(e -> e.getName() 
                     .equals(employee.getName())))); 
} 

Más información: http://source.coveo.com/2014/10/01/java8-mockito/

0

puede vincular el siguiente:

Mockito.verify(mockedObject).someMethodOnMockedObject(eq(desiredObject)) 

Esto verificará si el método de mockedObject se llama con desiredObject como parámetro .

0

¡El javadoc para refEq mencionó que la verificación de igualdad es superficial! Puede encontrar más detalles en el siguiente enlace:

[https://static.javadoc.io/org.mockito/mockito-core/2.2.29/org/mockito/ArgumentMatchers.html#refEq(T,%20java.lang.String...)][1]

"igualdad superficial" problema no se puede controlar cuando se utiliza otras clases que no se aplique el método .equals(), clase "DefaultMongoTypeMapper" es una ejemplo donde el método .equals() no está implementado.

org.springframework.beans.factory.support ofrece un método que puede generar una definición de bean en lugar de crear una instancia del objeto, y puede usarse para deshacerse de la falla de comparación.

genericBeanDefinition(DefaultMongoTypeMapper.class) 
         .setScope(SCOPE_SINGLETON) 
         .setAutowireMode(AUTOWIRE_CONSTRUCTOR) 
         .setLazyInit(false) 
         .addConstructorArgValue(null) 
         .getBeanDefinition() 

** "La definición de frijol es sólo una descripción del grano, no un grano de sí mismo. las descripciones de frijol implementan adecuadamente equals() y hashCode(), por lo que en lugar de crear una nueva DefaultMongoTypeMapper() nos proporcionar una definición que dice la primavera como debe crear una"

en su ejemplo, se puede hacer somethong como esto

Mockito.verify(mockedObject) 
     .doSoething(genericBeanDefinition(YourClass.class).setA("a") 
     .getBeanDefinition()); 
0

las soluciones anteriores no funcionó en mi caso. No pude usar ArgumentCaptor ya que el método fue llamado varias veces y necesitaba validar cada uno. Un simple Matcher con "argThat" hizo el truco fácilmente.

Matcher personalizada

// custom matcher 
private class PolygonMatcher extends ArgumentMatcher<PolygonOptions> { 
    private int fillColor; 
    public PolygonMatcher(int fillColor) { 
     this.fillColor = fillColor; 
    } 

    @Override 
    public boolean matches(Object argument) { 
     if (!(argument instanceof PolygonOptions)) return false; 
     PolygonOptions arg = (PolygonOptions)argument; 
     return Color.red(arg.getFillColor()) == Color.red(fillColor) 
       && Color.green(arg.getFillColor()) == Color.green(fillColor) 
       && Color.blue(arg.getFillColor()) == Color.blue(fillColor); 
    } 
} 

prueba Runner

// do setup work setup 
// 3 light green polygons 
int green = getContext().getResources().getColor(R.color.dmb_rx_bucket1); 
verify(map, times(3)).addPolygon(argThat(new PolygonMatcher(green))); 

// 1 medium yellow polygons 
int yellow = getContext().getResources().getColor(R.color.dmb_rx_bucket4); 
    verify(map, times(1)).addPolygon(argThat(new PolygonMatcher(yellow))); 

// 3 red polygons 
int orange = getContext().getResources().getColor(R.color.dmb_rx_bucket5); 
verify(map, times(3)).addPolygon(argThat(new PolygonMatcher(orange))); 

// 2 red polygons 
int red = getContext().getResources().getColor(R.color.dmb_rx_bucket7); 
verify(map, times(2)).addPolygon(argThat(new PolygonMatcher(red))); 
Cuestiones relacionadas