1
votes

Comment se moquer d'une méthode void avec Functional Interface / lambda param?

Comment puis-je me moquer d'une expression lambda qui est passée comme paramètre dans un appel de méthode void?

J'ai la structure de classe suivante que je dois tester, mais je ne peux même pas l'instancier à cause de son constructeur.

Existe-t-il un moyen de se moquer de l'appel de méthode someManager.doSomething ? Ou un moyen de se moquer de item.isDoItemSave?

Je ne peux pas le comprendre et SomeClass.setDoSave jette un pointeur nul sur l'appel de retour ( SomeClass line 18 ), puisque doSave est nul.

Classe que je souhaite instancier:

class SomeClassTest {

    private SomeClass someClass;

    @Mock
    private SomeManager someManagerMock;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.initMocks(this);
        this.someClass = new SomeClass(someManagerMock);
    }

    @Test
    void someClassTest() {
        someClass.anyOtherMethod();
    }

}

SomeManager.doSomething is void:

@FunctionalInterface
public interface ItemUpdate {
    void update(Item item);
}

ItemUpdate est une interface fonctionnelle:

public void doSomething(ItemUpdate update){
   Item item = new Item();
   update.update(item);
}

Je ne peux pas refactoriser ce constructeur, qui sait ce qui va se passer, le code est extrêmement couplé. Je veux juste pouvoir instancier SomeClass .

Ma classe de test ressemble à ceci, naturellement les tests échouent dans @BeforeEach sur SomeClass appel du constructeur:

public SomeClass() {

    private Boolean doSave;
    private SomeManager someManager;
    private SaveAction action;    

    public SomeClass(SomeManager someManager) {
        this.someManager = someManager;
        action = setDoSave() ? SAVE : null;
    } 

    private boolean setDoSave() {
        if(doSave == null) {
            someManager.doSomething(item -> {
                doSave = item.isDoItemSave();
            });
        }
        return doSave;
    }

}


8 commentaires

pouvez-vous spécifier plus de détails comme, le cas de test existant que vous avez écrit et le numéro de ligne où NullPointerException se produit


@AmitPatil s'il vous plaît lire ma question, je ne peux même pas instancier cette classe. Il n'y a pas de cas de test. J'ai ajouté ma classe de test et clarifié où le pointeur nul est lancé.


@curiosa J'ai ajouté le code de ma classe de test. J'ai du mal à comprendre comment me moquer de cette méthode vide, qui renvoie automatiquement une valeur via lambda.


Qu'est-ce que Item et que fait item.isDoItemSave () ?


@MaxVollmer Item n'est qu'un pojo. item.isDoItemSave () , comme la convention de dénomination l'implique, renvoie la valeur booléenne du champ doItemSave à l'intérieur de Item.


@curiosa Je sais, je l'ai fait mais ça ne va toujours pas exécuter doSave = item.isDoItemSave (); qui à son tour aboutira au même npe.


@MaxVollmer C'est du code réel, je devais juste renommer les choses. La question est, étant donné cette structure d'appel de méthode, quelle est une manière possible de se moquer d'elle?


@IgorFlakiewicz recherche doAnswer-when avec des membres mockito et moqueurs de void


3 Réponses :


0
votes

Je ne peux pas le comprendre et SomeClass.setDoSave lance un pointeur nul, puisque doSave est nul.

SomeClass.setDoSave renvoie NPE car la variable d'instance someManager est null .

Essayez d'ajouter @RunWith (MockitoJUnitRunner.class) à votre classe de test.


1 commentaires

Ce n'est pas vrai, premièrement, cette annotation n'est pas requise avec la façon dont mon test est structuré. 2ème Je sais exactement d'où vient le npe et je dois me moquer de doSave = item.isDoItemSave (); pour renvoyer une valeur booléenne. Je ne sais tout simplement pas comment faire ça.



1
votes

Pour l'instant, j'ai apporté des modifications pour que SomeClass s'instancie au moins. Leçon apprise, surveillez vos affectations de booléen à booléen.

    private boolean setDoSave() {
        if(doSave == null) {
            someManager.doSomething(item -> {
                doSave = item.isDoItemSave();
            });
        }

        return doSave != null ? doSave : false;
    }

Je laisse cette question ouverte en espérant que quelqu'un avec une meilleure connaissance des frameworks de moquerie puisse fournir un moyen de se moquer de ce cas.


0 commentaires

1
votes

Un rapide coup d'œil à la documentation montre l'exemple suivant que j'ai appliqué à votre situation

@BeforeEach
void setUp() {
    MockitoAnnotations.initMocks(this);

    //configure the mock
    // Java 8 - style 2 - assuming static import of AdditionalAnswers
    doAnswer(answerVoid(ItemUpdate update) -> {
        Item item = new Item();
        //...populate item as needed

        update.update(item);
    })
    .when(someManagerMock).doSomething(any(ItemUpdate.class));

    this.someClass = new SomeClass(someManagerMock);
}

Référence Prise en charge des réponses personnalisées Java 8

Notez que je n'ai pas testé cela. Je vais sur la base de ce qui a été montré dans la documentation.


1 commentaires

C'est génial, merci beaucoup. J'ai lu votre commentaire précédent et mis en œuvre exactement cela, juste avant de voir votre réponse. Merci encore. Je suppose que je dois entraîner mon google foo si je ne trouve pas ce document par moi-même. :)