web-dev-qa-db-fra.com

Comment vérifier que la méthode de vide statique a été appelée avec power mockito

J'utilise ce qui suit.

Powermock-mockito 1.5.12
Mockito 1.95
junit 4.11

Voici mon cours d'utils

public void InternalUtils {
    public static void sendEmail(String from, String[] to, String msg, String body) {
    }
}

voici le résumé de la classe sous test:

public class InternalService {
       public void processOrder(Order order) {
           if (order.isSuccessful()) {
               InternalUtils.sendEmail(...);
           }
       }
}

Et voici le test:

@PrepareForTest({InternalUtils.class})
@RunWith(PowerMockRunner.class)
public class InternalService {
   public void verifyEmailSend() {
        mockStatic(Internalutils.class);
        doNothing().when(InternalUtils, "sendEmail", anyString(), any(String.class), anyString(), anyString());
        Order order = mock(Order.class);
        when(order.isSuccessful()).thenReturn(true);
        InternalService is = new InternalService();

        verifyStatic(times(1));
        is.processOrder(order);
   }
}

Le test ci-dessus échoue. Le mode de vérification donné est aucun, mais selon le code, si la commande aboutit, un courriel doit être envoyé.

41
Chun ping Wang

Si vous vous moquez de ce comportement (avec quelque chose comme doNothing()), il ne devrait pas être nécessaire d'appeler verify*(). Cela dit, voici mon coup de pouce pour réécrire votre méthode de test:

@PrepareForTest({InternalUtils.class})
@RunWith(PowerMockRunner.class)
public class InternalServiceTest { //Note the renaming of the test class.
   public void testProcessOrder() {
        //Variables
        InternalService is = new InternalService();
        Order order = mock(Order.class);

        //Mock Behavior
        when(order.isSuccessful()).thenReturn(true);
        mockStatic(Internalutils.class);
        doNothing().when(InternalUtils.class); //This is the preferred way
                                               //to mock static void methods.
        InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());

        //Execute
        is.processOrder(order);            

        //Verify
        verifyStatic(InternalUtils.class); //Similar to how you mock static methods
                                           //this is how you verify them.
        InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());
   }
}

Je me suis regroupé en quatre sections pour mieux mettre en évidence ce qui se passe:

1. Variables

J'ai choisi de déclarer ici toutes variables d'instance/arguments de méthode/collaborateurs factices. S'il s'agit de quelque chose utilisé dans plusieurs tests, envisagez d'en faire une variable d'instance de la classe de test.

2. Comportement factice

C'est ici que vous définissez le comportement de toutes vos simulacres. Vous définissez ici les valeurs de retour et les attentes avant d'exécuter le code testé. En règle générale, si vous définissez le comportement fictif ici, vous ne devrez pas vérifier le comportement plus tard.

3. Exécuter

Rien d'extraordinaire ici; cela lance juste le code en cours de test. J'aime lui donner sa propre section pour attirer l'attention sur elle.

4. Vérifier

C'est à ce moment-là que vous appelez une méthode commençant par verify ou assert. Une fois le test terminé, vous vérifiez que les événements souhaités ont bien eu lieu. C'est la plus grande erreur que je vois avec votre méthode de test; vous avez essayé de vérifier l'appel de la méthode avant même de lui donner une chance de s'exécuter. Deuxièmement, vous n'avez jamais spécifié la méthode statique à vérifier.

Notes complémentaires

C'est surtout une préférence personnelle de ma part. Il y a un certain ordre dans lequel vous devez faire les choses, mais au sein de chaque groupe, il y a une petite marge de manœuvre. Cela m'aide à distinguer rapidement ce qui se passe où.

Je recommande également vivement de passer en revue les exemples sur les sites suivants, car ils sont très robustes et peuvent vous aider dans la majorité des cas dont vous aurez besoin:

53
Matt Lachman

Tu la réponse ci-dessus est largement acceptée et bien documentée, j'ai trouvé une raison de poster ma réponse ici: -

    doNothing().when(InternalUtils.class); //This is the preferred way
                                           //to mock static void methods.
    InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());

Ici, je ne comprends pas pourquoi nous appelons nous-mêmes InternalUtils.sendEmail. J'expliquerai dans mon code pourquoi nous n'avons pas besoin de faire cela.

mockStatic(Internalutils.class);

Nous nous sommes donc moqués de la classe, ce qui est bien. Voyons maintenant comment nous devons vérifier la méthode sendEmail (/..../).

@PrepareForTest({InternalService.InternalUtils.class})
@RunWith(PowerMockRunner.class)
public class InternalServiceTest {

    @Mock
    private InternalService.Order order;

    private InternalService internalService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        internalService = new InternalService();
    }

    @Test
    public void processOrder() throws Exception {

        Mockito.when(order.isSuccessful()).thenReturn(true);
        PowerMockito.mockStatic(InternalService.InternalUtils.class);

        internalService.processOrder(order);

        PowerMockito.verifyStatic(times(1));
        InternalService.InternalUtils.sendEmail(anyString(), any(String[].class), anyString(), anyString());
    }

}

La magie se trouve dans ces deux lignes. Première ligne indique au framework PowerMockito qu'il doit vérifier la classe dont il se moque de manière statique. Mais quelle méthode faut-il vérifier? La deuxième ligne indique la méthode à vérifier.

PowerMockito.verifyStatic(times(1));
InternalService.InternalUtils.sendEmail(anyString(), any(String[].class), anyString(), anyString());

Ceci est le code de ma classe, sendEmail api deux fois.

public class InternalService {

    public void processOrder(Order order) {
        if (order.isSuccessful()) {
            InternalUtils.sendEmail("", new String[1], "", "");
            InternalUtils.sendEmail("", new String[1], "", "");
        }
    }

    public static class InternalUtils{

        public static void sendEmail(String from, String[]  to, String msg, String body){

        }

    }

    public class Order{

        public boolean isSuccessful(){
            return true;
        }

    }

}

Comme il appelle deux fois, il vous suffit de modifier le verify (times (2)) ... c'est tout.

16
Arpit