2012-01-31 20 views
13

Tengo una clase Foo que es SUT y una clase Bar, que es su colaboradora. Foo llama al run(List<Object> values) en el Bar con "expectedList" como argumento. Luego, Foo agregará algunos elementos más a este List para que su estado sea diferente de lo que era en el momento de llamar al run(). Aquí está mi caso de prueba.¿Puede Mockito verificar los parámetros en función de sus valores en el momento de la llamada al método?

@Test 
public void testFoo() { 
    Bar collaborator = spy(new Bar()); 
    Foo sut = new Foo(collaborator); 
    verify(collaborator).run(expectedList); 
} 

Tenga en cuenta que el colaborador es en realidad un objeto espía en lugar de un simulacro. Este caso de prueba fallará porque aunque se llamó a run() con un argumento igual a expectedList, se modificó desde entonces y su valor actual ya no es igual a expectedList. Sin embargo, esta es la forma en que se supone que funciona, así que me pregunto si hay una forma de que Mockito almacene la instantánea de los parámetros cuando se llama a un método y los verifica en base a estos valores en lugar de los valores más recientes.

Respuesta

11

utilizar un Answer para comprobar el valor del argumento cuando se llama al método. Puede lanzar un AssertionError dentro del Answer si el valor es incorrecto, o puede almacenar el valor, y hacer su afirmación al final.

+0

Sí David tiene razón. Debido a la forma en que se elabora la API de Mockito, no es posible verificar varias llamadas con la misma referencia de argumento. EasyMock puede hacerlo porque tiene una fase de expectativa antes de ejecutar el código de producción. De todos modos, en lugar de una 'Respuesta' uso un' ArgurmentCaptor' y escribo una o más aserciones sobre el estado final de esa lista, es decir, con FEST-Assert 'assertThat (captor.getValue()). Contains (" A "," B ") .contains (" T "," U ");' – Brice

+0

@Brice - ¿Cómo funcionaría eso de manera diferente al enfoque de Michael Wiles? –

+0

No lo es. Es solo una forma diferente de lograr el propósito de la prueba. Porque la mayoría de las veces no es necesario verificar los argumentos intermedios, sino simplemente que se produjeron algunas interacciones y el resultado final.Aunque debo decir que si Tom tenía requisitos específicos, aceptó que esto no lo ayudaría, pero en este caso evitaría objetos mutables en mi código de producción. Parece que los mensajes entre dos colaboradores y los mensajes siempre deben ser inmutables. – Brice

0

No puede llamar al verify() en un objeto que no es mock. ¿Es esto lo que querías decir?

Bar collaborator = mock(Bar.class); 
Foo sut = spy(new Foo(collaborator)); 
verify(collaborator).run(expectedList); 
+0

Gracias, el código de ejemplo tenía un error y lo corrigí. Sin embargo, esa no es mi pregunta. Se trata de poder verificar un argumento basado en su valor en el momento de la llamada al método, no en el más reciente. –

-1

¿Por qué no intentas usar la captura de argumentos para adquirir el valor de la lista esperada cuando se ejecutó y luego puedes compararla?

ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class); 

verify(collaborator).run(listCaptor.capture()); 

assertEquals(expectedList, argument.getValue()); 
+6

Si su lista modificada es la misma instancia, entonces argument.getValue() devolverá la instancia 'expectedList', no una copia, así que esto es esencialmente lo mismo que está haciendo, ¿no es así? – jhericks

+0

@Michael Wiles Gracias, pero como mencionó Jhericks, ArgumentCaptor captura la instancia de la lista original. –

+0

Disculpe, Michael, he votado negativamente su respuesta porque su solución tiene exactamente el mismo problema que la prueba del OP, según lo explicado por jhericks. –

1

The answer of Dawood ibn Kareem trabajaron para mí, pero me faltaba un ejemplo, yo también uso Kotlin y Mockito-Kotlin, así que mi solución es la siguiente:

class Foo(var mutable: String) 

interface Bar { 
    fun run(foo: Foo) 
} 

@Test fun `validate mutable parameter at invocation`() { 
    val bar = mock<Bar>() 

    var valueAtInvocation: String? = null 
    whenever(bar.run(any())).then { 
     val foo = it.arguments.first() as Foo 
     valueAtInvocation = foo.mutable // Store mutable value as it was at the invocation 
     Unit // The answer 
    } 

    val foo = Foo(mutable = "first") 
    bar.run(foo) 
    valueAtInvocation isEqualTo "first" 

    foo.mutable = "second" 
    bar.run(foo) 
    valueAtInvocation isEqualTo "second" 
} 

valueAtInvocation representará el valor de la propiedad mutable foo.mutable en la última invocación de bar.run(foo). También debería ser posible hacer aserciones dentro del bloque then {}.

Cuestiones relacionadas