Je suis un novice en développement et en tests unitaires en particulier. Je suppose que mon exigence est assez simple, mais je souhaite connaître l'opinion des autres à ce sujet.
Supposons que j'ai deux classes comme ça -
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
Disons que j'écris un test unitaire pour tester First.doSecond()
méthode de . Cependant, supposons que je veuille moquer la Second.doSecond()
classe comme ça. J'utilise Mockito pour ce faire.
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
Je vois que la moquerie n'a pas d'effet et que l'assertion échoue. N'existe-t-il aucun moyen de se moquer des variables membres d'une classe que je souhaite tester. ?
Ce n'est pas possible si vous ne pouvez pas modifier votre code. Mais j'aime l'injection de dépendances et Mockito le prend en charge:
Votre test:
C'est très agréable et facile.
la source
Si vous regardez attentivement votre code, vous verrez que la
second
propriété de votre test est toujours une instance deSecond
, pas une simulation (vous ne transmettez pas la simulationfirst
dans votre code).Le moyen le plus simple serait de créer un setter pour
second
enFirst
classe et de lui passer explicitement le simulacre.Comme ça:
Un autre serait de passer une
Second
instance en tant queFirst
paramètre de constructeur de.Si vous ne pouvez pas modifier le code, je pense que la seule option serait d'utiliser la réflexion:
Mais vous pouvez probablement, car il est rare de faire des tests sur du code que vous ne contrôlez pas (bien que l'on puisse imaginer un scénario où vous devez tester une bibliothèque externe car son auteur ne l'a pas fait :))
la source
@Mock
et annoter First avec@InjectMocks
et instancier First dans l'initialiseur. Mockito fera automatiquement de son mieux pour trouver un endroit pour injecter la deuxième maquette dans la première instance, y compris en définissant des champs privés qui correspondent au type.@Mock
était autour de 1,5 (peut-être plus tôt, je ne suis pas sûr). 1.8.3 introduit@InjectMocks
ainsi que@Spy
et@Captor
.Si vous ne pouvez pas modifier la variable membre, l'inverse est d'utiliser powerMockit et d'appeler
Maintenant, le problème est que TOUT appel à new Second renverra la même instance simulée. Mais dans votre cas simple, cela fonctionnera.
la source
J'ai eu le même problème où une valeur privée n'était pas définie car Mockito n'appelle pas les super constructeurs. Voici comment j'augmente la moquerie par la réflexion.
Tout d'abord, j'ai créé une classe TestUtils qui contient de nombreux outils utiles, y compris ces méthodes de réflexion. L'accès à la réflexion est un peu bancal à mettre en œuvre à chaque fois. J'ai créé ces méthodes pour tester du code sur des projets qui, pour une raison ou une autre, n'avaient pas de package moqueur et je n'ai pas été invité à l'inclure.
Ensuite, je peux tester la classe avec une variable privée comme celle-ci. Ceci est utile pour se moquer des arbres de classes que vous n'avez pas de contrôle également.
J'ai modifié mon code de mon projet actuel ici, en page. Il pourrait y avoir un problème de compilation ou deux. Je pense que vous avez une idée générale. N'hésitez pas à saisir le code et à l'utiliser si vous le trouvez utile.
la source
Beaucoup d'autres vous ont déjà conseillé de repenser votre code pour le rendre plus testable - de bons conseils et généralement plus simples que ce que je suis sur le point de suggérer.
Si vous ne pouvez pas modifier le code pour le rendre plus testable, PowerMock: https://code.google.com/p/powermock/
PowerMock étend Mockito (vous n'avez donc pas besoin d'apprendre un nouveau framework fictif), fournissant des fonctionnalités supplémentaires. Cela inclut la possibilité qu'un constructeur renvoie une maquette. Puissant, mais un peu compliqué - alors utilisez-le judicieusement.
Vous utilisez un autre coureur Mock. Et vous devez préparer la classe qui va appeler le constructeur. (Notez qu'il s'agit d'un piège courant - préparez la classe qui appelle le constructeur, pas la classe construite)
Ensuite, dans votre configuration de test, vous pouvez utiliser la méthode whenNew pour que le constructeur renvoie un simulacre
la source
Oui, cela peut être fait, comme le montre le test suivant (écrit avec l'API de simulation JMockit, que je développe):
Avec Mockito, cependant, un tel test ne peut pas être écrit. Cela est dû à la façon dont la moquerie est implémentée dans Mockito, où une sous-classe de la classe à moquer est créée; seules les instances de cette sous-classe «fictive» peuvent avoir un comportement simulé, vous devez donc faire en sorte que le code testé les utilise au lieu de toute autre instance.
la source
Si vous voulez une alternative à ReflectionTestUtils de Spring dans mockito, utilisez
la source