Comment faire pour simuler les méthodes avec mockito

Comment simuler des méthodes avec le type de retour vide?

J’ai implémenté un pattern Observer mais je ne peux pas me moquer de lui avec Mockito car je ne sais pas comment.

Et j’ai essayé de trouver un exemple sur Internet, mais je n’ai pas réussi.

Ma classe ressemble à

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 ssortingng 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(); } 

Le système n’est pas déclenché par simulation. = (Je veux montrer l’état du système mentionné ci-dessus. Et faire l’affirmation selon eux.

Jetez un coup d’œil aux documents de l’ API Mockito. Comme le mentionne le document lié (Point n ° 12), vous pouvez utiliser toute la famille de méthodes doThrow() , doAnswer() , doNothing() , doReturn() du framework Mockito pour simuler des méthodes vides.

Par exemple,

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

ou si vous voulez le combiner avec un comportement de suivi,

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

En supposant que vous cherchiez à railler le setter setState(Ssortingng s) dans la classe World, le code utilise la méthode doAnswer pour setState le 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.toSsortingng(args)); return null; } }).when(mockWorld).setState(anySsortingng()); 

Je pense avoir trouvé une réponse plus simple à cette question, appeler la méthode réelle pour une seule méthode (même si elle a un retour vide), vous pouvez le faire:

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

Ou, vous pouvez appeler la méthode réelle pour toutes les méthodes de cette classe, en procédant comme suit:

   = mock(.class, Mockito.CALLS_REAL_METHODS); 

En ajoutant à ce que @sateesh a dit, lorsque vous voulez simplement simuler une méthode vide afin d’empêcher le test de l’appeler, vous pouvez utiliser un Spy cette manière:

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

Lorsque vous souhaitez exécuter votre test, assurez-vous d’appeler la méthode en test sur l’object spy et non sur l’object world . Par exemple:

 assertEquals(0,spy.methodToTestThatShouldReturnZero()); 

La solution du soi-disant problème est d’utiliser un spy Mockito.spy (…) au lieu d’un mock Mockito.mock (..) .

Spy nous permet de nous moquer partiellement. Mockito est bon à ce sujet. Comme vous avez une classe qui n’est pas complète, de cette manière, vous vous moquez d’une place requirejse dans cette classe.

Tout d’abord: vous devez toujours importer mockito static, de cette façon le code sera beaucoup plus lisible (et intuitif):

 import static org.mockito.Mockito.*; 

Pour des moqueries partielles et garder toujours la fonctionnalité originale sur le rest, mockito propose “Spy”.

Vous pouvez l’utiliser comme suit:

 private World world = spy(World.class); 

Pour éliminer l’exécution d’une méthode, vous pouvez utiliser quelque chose comme ceci:

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

pour donner un comportement personnalisé à une méthode, utilisez “when” avec un “thenReturn”:

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

Pour plus d’exemples, veuillez trouver les exemples de mockito dans la doc.

Comment simuler des méthodes vides avec mockito – il y a deux options:

  1. doAnswer – Si nous voulons que notre méthode vide simulée fasse quelque chose (se moquer du comportement malgré son annulation).
  2. doThrow – Ensuite, il y a Mockito.doThrow() si vous voulez lancer une exception à partir de la méthode Mockito.doThrow() .

Voici un exemple d’utilisation (pas une firebase database idéale, mais simplement pour illustrer l’utilisation de base).

 @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]; Ssortingng email = (Ssortingng) arguments[1]; customer.setEmail(email); } return null; } }).when(daoMock).updateEmail(any(Customer.class), any(Ssortingng.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(Ssortingng.class)); // calling the method under test Customer customer = service.changeEmail("old@test.com", "new@test.com"); } } 

Vous pouvez trouver plus de détails sur la façon de simuler et de tester les méthodes vides avec Mockito dans mon post Comment se moquer de Mockito (Un guide complet avec des exemples)

Ajouter une autre réponse au groupe (sans jeu de mots) …

Vous devez appeler la méthode doAnswer si vous ne pouvez pas utiliser spy. Cependant, vous n’avez pas nécessairement besoin de répondre par vous-même. Il existe plusieurs implémentations par défaut. Notamment, CallsRealMethods .

En pratique, cela ressemble à ceci:

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

Ou:

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

Je pense que vos problèmes sont dus à votre structure de test. J’ai eu du mal à combiner la méthode traditionnelle d’implémentation des interfaces dans la classe de test (comme vous l’avez fait ici).

Si vous implémentez l’écouteur en tant que Mock, vous pouvez alors vérifier l’interaction.

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

Cela devrait vous convaincre que le monde fait ce qu’il faut.

En Java 8, cela peut être un peu plus propre, en supposant que vous ayez une importation statique pour org.mockito.Mockito.doAnswer :

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

Le return null; est important et sans cela, la compilation échouera avec des erreurs assez obscures car elle ne pourra pas trouver un remplacement approprié pour doAnswer .

Par exemple, un ExecutorService qui exécute immédiatement tout Runnable passé à execute() pourrait être implémenté en utilisant:

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

@ashley: travaille pour moi

 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); } }