Cómo hacer simulacros a métodos vacíos con mockito

¿Cómo simular métodos con el tipo de devolución de nulo?

Implementé un patrón de Observer pero no puedo simularlo con Mockito porque no sé cómo.

Y traté de encontrar un ejemplo en Internet, pero no tuve éxito.

Mi clase parece

public class World { List listeners; void addListener(Listener item) { listeners.add(item); } void doAction(Action goal,Object obj) { setState("i received"); goal.doAction(obj); setState("i finished"); } private string state; //setter getter state } public class WorldTest implements Listener { @Test public void word{ World w= mock(World.class); w.addListener(this); ... ... } } interface Listener { void doAction(); } 

El sistema no se activa con simulacro. = (Quiero mostrar el estado del sistema mencionado anteriormente y hacer una afirmación de acuerdo con ellos.

Eche un vistazo a los documentos de la API Mockito. Como menciona el documento vinculado (Punto n. ° 12), puede utilizar cualquiera de las familias de métodos doThrow() , doAnswer() , doNothing() , doReturn() de Mockito framework para simular métodos vacíos.

Por ejemplo,

 Mockito.doThrow(new Exception()).when(instance).methodName(); 

o si desea combinarlo con el comportamiento de seguimiento,

 Mockito.doThrow(new Exception()).doNothing().when(instance).methodName(); 

Suponiendo que está buscando burlarse del setter setState(String s) en la clase World de abajo, el código usa el método doAnswer para setState el setState .

 World mockWorld = mock(World.class); doAnswer(new Answer() { public Void answer(InvocationOnMock invocation) { Object[] args = invocation.getArguments(); System.out.println("called with arguments: " + Arrays.toString(args)); return null; } }).when(mockWorld).setState(anyString()); 

Creo que encontré una respuesta más simple a esa pregunta, para llamar al método real para un solo método (incluso si tiene un retorno nulo) puedes hacer esto:

 Mockito.doCallRealMethod().when().(); .(); 

O bien, puede llamar al método real para todos los métodos de esa clase, haciendo esto:

   = mock(.class, Mockito.CALLS_REAL_METHODS); 

Agregando a lo que dijo @sateesh, cuando solo quiere burlarse de un método nulo para evitar que la prueba lo llame, puede usar un Spy esta manera:

 World world = new World(); World spy = Mockito.spy(world); Mockito.doNothing().when(spy).methodToMock(); 

Cuando desee ejecutar su prueba, asegúrese de llamar al método en prueba en el objeto spy y no en el objeto world . Por ejemplo:

 assertEquals(0,spy.methodToTestThatShouldReturnZero()); 

La solución del llamado problema es usar un spy Mockito.spy (…) en lugar de un mock Mockito.mock (..) .

Spy nos permite burlarse parcialmente. Mockito es bueno en este asunto. Debido a que tiene una clase que no está completa, de esta manera se burla de algún lugar requerido en esta clase.

Antes que nada: siempre debes importar mockito static, de esta forma el código será mucho más legible (e intuitivo):

 import static org.mockito.Mockito.*; 

Para burlarse parcialmente y mantener la funcionalidad original en el rest, mockito ofrece “Spy”.

Puedes usarlo de la siguiente manera:

 private World world = spy(World.class); 

Para eliminar la ejecución de un método, puede usar algo como esto:

 doNothing().when(someObject).someMethod(anyObject()); 

para dar un comportamiento personalizado a un método use “cuándo” con un “thenReturn”:

 doReturn("something").when(this.world).someMethod(anyObject()); 

Para obtener más ejemplos, encuentre las muestras de mockito en el documento.

Cómo simular métodos vacíos con mockito: hay dos opciones:

  1. doAnswer – Si queremos que nuestro método vacío anulado haga algo (se burla del comportamiento a pesar de ser nulo).
  2. doThrow – Luego está Mockito.doThrow() si desea lanzar una excepción desde el método void void.

A continuación se muestra un ejemplo de cómo usarlo (no es un uso ideal pero solo quería ilustrar el uso básico).

 @Test public void testUpdate() { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Object[] arguments = invocation.getArguments(); if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) { Customer customer = (Customer) arguments[0]; String email = (String) arguments[1]; customer.setEmail(email); } return null; } }).when(daoMock).updateEmail(any(Customer.class), any(String.class)); // calling the method under test Customer customer = service.changeEmail("old@test.com", "new@test.com"); //some asserts assertThat(customer, is(notNullValue())); assertThat(customer.getEmail(), is(equalTo("new@test.com"))); } @Test(expected = RuntimeException.class) public void testUpdate_throwsException() { doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class)); // calling the method under test Customer customer = service.changeEmail("old@test.com", "new@test.com"); } } 

Puede encontrar más detalles sobre cómo simular y probar métodos vacíos con Mockito en mi publicación Cómo burlarse con Mockito (Una guía completa con ejemplos)

Agregando otra respuesta al grupo (sin juego de palabras) …

Debe llamar al método doAnswer si no puede \ no desea usar espías. Sin embargo, no necesariamente necesita lanzar su propia Respuesta . Hay varias implementaciones predeterminadas. Notablemente, CallsRealMethods .

En la práctica, se ve algo como esto:

 doAnswer(new CallsRealMethods()).when(mock) .voidMethod(any(SomeParamClass.class)); 

O:

 doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock) .voidMethod(any(SomeParamClass.class)); 

Creo que tus problemas se deben a tu estructura de prueba. Me ha resultado difícil mezclar burlas con el método tradicional de implementación de interfaces en la clase de prueba (como lo ha hecho aquí).

Si implementa el oyente como un simulacro, puede verificar la interacción.

 Listener listener = mock(Listener.class); w.addListener(listener); world.doAction(..); verify(listener).doAction(); 

Esto debería satisfacerte de que el ‘Mundo’ está haciendo lo correcto.

En Java 8 esto puede hacerse un poco más limpio, suponiendo que tiene una importación estática para org.mockito.Mockito.doAnswer :

 doAnswer(i -> { // Do stuff with i.getArguments() here return null; }).when(*mock*).*method*(*methodArguments*); 

El return null; es importante y sin eso la comstackción fallará con algunos errores bastante oscuros ya que no podrá encontrar una anulación adecuada para doAnswer .

Por ejemplo, un ExecutorService que ejecute inmediatamente cualquier Runnable pasado a execute() podría implementarse usando:

 doAnswer(i -> { ((Runnable) i.getArguments()[0]).run(); return null; }).when(executor).execute(any()); 

@ashley: funciona para mí

 public class AssetChangeListenerImpl extends AbstractAssetChangeListener implements AssetChangeListener { @Override public void onChangeEvent(final EventMessage message) throws EventHubClientException { execute(message); } } } public class AbstractAssetChangeListener { protected void execute( final EventMessage message ) throws EventHubClientException { executor.execute( new PublishTask(getClient(), message) ); } } @RunWith(MockitoJUnitRunner.class) public class AssetChangeListenerTest extends AbstractAssetChangeListenerTest { public void testExecute() throws EventHubClientException { EventMessage message = createEventMesage(EventType.CREATE); assetChangeListener.execute(message); verify(assetChangeListener, times(1)).execute(message); } }