11
votes

Comment utiliser PowerMockito pour se moquer de la construction de nouveaux objets lors du test d'une méthode dans une classe anonyme?

Je voudrais écrire un test Junit pour vérifier que le code ci-dessous utilise une bufferedInputStream: xxx

(filaireFactory est une interface.)

mon test jusqu'à présent ressemble à ceci: xxx

L'appel à PowerMockito.spy augmente une exception avec ce message: xxx

Que dois-je utiliser au lieu de PowerMocktio.spy pour configurer les appels vers quandNew?


0 commentaires

4 Réponses :


0
votes

Vous devez exécuter le test à l'aide du coureur PowerMockito et vous devez indiquer le cadre que la classe (ES) doit avoir un comportement personnalisé. Ajoutez les annotations de classe suivantes sur votre classe de test:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ BufferedInputStream.class })


1 commentaires

Les annotations ne sont pas le problème. Si je change INPUTHELPER.BZIP2_Factory d'une classe interne anonyme en une classe intérieure nommée, alors cela fonctionne.



0
votes

Je viens de venir autour du même problème. Donc, selon le Documentation de Constructor Mocking Vous devez préparer la classe, qui sera créer la classe diabolique (s). Dans votre cas, les classes méchantes sont bufferedInputStream et CBZIP2InputStream, et le créateur d'entre eux est une classe anonyme, qui ne peut pas être définie dans la préparation d'annotations. Je devais donc faire la même chose que vous le faites (HMM, vient de voir votre commentaire), je déplacé la classe anonyme à Named Classe .


0 commentaires

13
votes

Le message est assez évident: vous ne pouvez pas vous moquer de classes non visibles et finales. Réponse courte: Créez une classe nommée forte> de votre anonyme, et Testez cette classe strong>!

réponse longue, creusons pourquoi! P>

La classe anonyme est finale h2>

vous instaniez une classe anonyme de FilterFactory code>, lorsque le compilateur voit une classe anonyme, il crée un paquet FINAL STRAND> ET visible strong> classe. De sorte que la classe anonyme ne se moque pas par la moyenne standard, c'est-à-dire via Mockito. P>

Mocking anonyme Classe: possible mais fragile Si non hacky h2>

OK, supposons maintenant que vous souhaitiez être capable de se moquer de cette classe anonyme à travers PowerMock. Les compilateurs actuels compilent la classe anonyme avec le schéma suivant: p> xxx pré>

la classe anonyme moqueur possible mais fragile (et je le veux dire) Donc, supposant que la classe anonyme soit le onzième à déclarer, il apparaîtra comme p> xxx pré>

afin que vous puissiez vous préparer à tester la classe anonyme: p> xxx PRE>

Ce code va compilera, mais sera éventuellement signalé comme une erreur avec votre IDE. L'IDE ne sait probablement pas sur InputHelper 11.class code>. Intellij qui n'utilise pas la classe compilée pour vérifier le rapport de code. P>

Le fait que le nommage de la classe anonyme dépend réellement de l'ordre de la déclaration est un problème, lorsque quelqu'un ajoute une autre classe anonyme avant, la numérotation pourrait changer. Les cours anonymes sont faits pour rester anonyme, que si les gars du compilateur décident d'un jour d'utiliser des lettres ou même des identifiants aléatoires! P>

Les classes anonymes de SOWERMOCK sont aussi cassantes que dans un véritable projet! strong> p>

Note modifiée: strong> Le compilateur Eclipse a un système de numérotation différent, il utilise toujours un numéro à 3 chiffres: P>

@RunWith(PowerMockRunner.class)
public class BufferedBZIP2FilterFactoryTest {

    @Test
    @PrepareForTest({BufferedBZIP2FilterFactory.class})
    public void wraps_InputStream_in_BufferedInputStream() throws Exception {
        whenNew(CBZip2InputStream.class).withArguments(isA(BufferedInputStream.class))
                .thenReturn(Mockito.mock(CBZip2InputStream.class));

        new BufferedBZIP2FilterFactory().makeFilter(anInputStream());

        verifyNew(CBZip2InputStream.class).withArguments(isA(BufferedInputStream.class));
    }

    private ByteArrayInputStream anInputStream() {
        return new ByteArrayInputStream(new byte[10]);
    }
}


3 commentaires

+1 pour la classe intérieure de 1 $ :) J'y ai pensé, mais je n'ai pas osé l'essayer. D'autre part, pour de courtes classes, je préférerais utiliser une classe anonyme et la classe de 1 $. C'est juste moche de nommer une classe uniquement pour les tests.


Oui, je suis d'accord, mais dans ce cas, la classe anonyme est assez simple et n'aura pas besoin d'une telle configuration des tests lourds. Dans le cas de Zack, il semble qu'il traitait avec plus de code dans la classe intérieure. À la fin, cela dépend de la criticité de ce qui est testé, s'il est considéré comme important, le code lui-même doit être remarquable à ce sujet.


Grâce à vous, je me rends compte que j'ai manqué de connaissances importantes. J'utilise une classe UTILS (ou assistant) pour réduire le code de création et de test de la classe abstraite et, bien sûr, je veux les espionner. C'était une erreur, alors maintenant, je crée une simple classe d'extension dans des sources de test et espionner cela à la place et son ok



9
votes

Old Post, mais vous n'avez pas besoin de créer une classe nommée - Utilisez des caractères génériques, comme mentionné dans cet article PowerMock Constructeur de moquure via une nouvelle () ne fonctionne pas avec une classe anonyme

@Preparifortest (nom entièrementqualifiednames = "com.yourpackage.coning.anonClass. *")


1 commentaires

C'est la bonne réponse. Mais si vous êtes PowerMocking une classe individuelle, il pourrait ressembler à @preparfortest (noms entièrementqualifiednames = "com.yourpackage.yourclass *")