Comment faire des méthodes mock to void avec mockito
comment simuler des méthodes avec le type de retour de vide?
j'ai mis en place un modèle D'observateur mais je ne peux pas me moquer avec Mockito parce que je ne sais pas comment.
et j'ai essayé de trouver un exemple sur Internet, mais sans succès.
ma classe ressemble à
public class World {
List<Listener> 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();
}
le système n'est pas déclenché avec mock. =( Je veux montrer l'état du système mentionné ci-dessus. Et faire des affirmations selon eux.
10 réponses
regardez le Mockito API docs . Comme le document lié le mentionne (Point # 12), Vous pouvez utiliser n'importe lequel des doThrow()
, doAnswer()
, doNothing()
, doReturn()
famille de méthodes du cadre de Mockito aux méthodes du vide simulé.
par exemple,
Mockito.doThrow(new Exception()).when(instance).methodName();
ou si vous souhaitez les combiner avec un suivi de comportement,
Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();
présumant que vous regardez se moquer de la setter setState(String s)
dans la classe monde ci-dessous est le code utilise doAnswer
méthode pour moquer le setState
.
World mockWorld = mock(World.class);
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(mockWorld).setState(anyString());
je pense que j'ai trouvé une réponse plus simple à cette question, pour appeler la vraie méthode pour une seule méthode (même si elle a un retour de vide) vous pouvez faire ceci:
Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();
ou, vous pourriez appeler la vraie méthode pour toutes les méthodes de cette classe, faisant ceci:
<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
ajoutant à ce que @sateesh a dit, quand vous voulez juste vous moquer d'une méthode de vide afin d'empêcher le test de l'appeler, vous pouvez utiliser un Spy
de cette façon:
World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();
lorsque vous voulez exécuter votre test, assurez-vous d'appeler la méthode en test sur l'objet spy
et non sur l'objet world
. Par exemple:
assertEquals(0,spy.methodToTestThatShouldReturnZero());
la solution du soi-disant problème est d'utiliser un spy
Mockito.espion.(..) au lieu d'un mock
Mockito.moquer.(.) .
Spy nous permet de nous moquer partiellement. Mockito est bon à ce sujet. Parce que vous avez une classe qui n'est pas complète, de cette façon vous vous moquez d'une place requise dans cette classe.
tout D'abord: vous devez toujours importer mockito statique, de cette façon le code sera beaucoup plus lisible (et intuitif):
import static org.mockito.Mockito.*;
pour la moquerie partielle et toujours garder la fonctionnalité originale sur le mockito de repos offre "Espion".
Vous pouvez l'utiliser comme suit:
private World world = spy(World.class);
pour éliminer une méthode d'être exécuté vous pourriez utiliser quelque chose comme ceci:
doNothing().when(someObject).someMethod(anyObject());
pour donner comportement personnalisé à une utilisation de méthode "quand" avec un "thenReturn":
doReturn("something").when(this.world).someMethod(anyObject());
pour plus d'exemples, veuillez trouver les échantillons de mockito dans le doc.
comment simuler des méthodes de vide avec mockito - il y a deux options:
-
doAnswer
- si nous voulons que notre méthode du vide moqué fasse quelque chose (moquez le comportement malgré être vide). -
doThrow
- puis il y aMockito.doThrow()
si vous voulez jeter une exception de la méthode mocked void.
ci-dessous est un exemple de la façon de l'utiliser (pas une usecase idéal, mais juste voulu illustrer l'utilisation de base).
@Test
public void testUpdate() {
doAnswer(new Answer<Void>() {
@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");
}
}
vous pourriez trouver plus de détails sur la façon de mock et test nul méthodes avec Mockito dans mon post comment moquer avec Mockito (un guide complet avec des exemples)
ajout d'une autre réponse au groupe (sans jeu de mots)...
vous ne devez appeler la méthode doAnswer si vous ne pouvez pas\don't want to use spy's. Cependant, vous n'avez pas nécessairement besoin de lancer votre propre réponse . Il existe plusieurs implémentations par défaut. Notamment, Appelle Les Méthodes Réelles .
dans la pratique, il ressemble à quelque chose comme 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 trouvé difficile de mélanger la moquerie avec la méthode traditionnelle d'implémentation des interfaces dans la classe test (comme vous l'avez fait ici).
si vous implémentez l'auditeur comme une simulation, vous pouvez alors vérifier l'interaction.
Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();
cela devrait vous satisfaire que le "monde" fait la bonne chose.
en Java 8 cela peut être fait un peu plus propre, en supposant que vous avez 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 lui la compilation échouera avec quelques erreurs assez obscures car il ne sera pas en mesure de trouver un contrôleur approprié pour doAnswer
.
par exemple, un ExecutorService
qui exécute immédiatement n'importe quel Runnable
passé à execute()
pourrait être mis en œuvre en utilisant:
doAnswer(i -> {
((Runnable) i.getArguments()[0]).run();
return null;
}).when(executor).execute(any());
@ashley : fonctionne 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); } }