Comment simuler une méthode privée d'essai en utilisant PowerMock?

j'ai une classe que je voudrais tester avec une méthode publique qui appelle privée. Je suppose que la méthode privée fonctionne correctement. Par exemple, je voudrais quelque chose comme doReturn....when... . J'ai découvert qu'il existe une solution possible en utilisant PowerMock , mais cette solution ne fonctionne pas pour moi. Comment peut-Il être fait? Quelqu'un a ce problème?

55
demandé sur ArtB 2011-10-18 11:41:23

4 réponses

Je ne vois pas de problème ici. Avec le code suivant qui utilise L'API Mockito, j'ai réussi à faire exactement cela:

public class CodeWithPrivateMethod {

    public void meaningfulPublicApi() {
        if (doTheGamble("Whatever", 1 << 3)) {
            throw new RuntimeException("boom");
        }
    }

    private boolean doTheGamble(String whatever, int binary) {
        Random random = new Random(System.nanoTime());
        boolean gamble = random.nextBoolean();
        return gamble;
    }
}

et voici le test de JUnit:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {

    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());

        when(spy, method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                .withArguments(anyString(), anyInt())
                .thenReturn(true);

        spy.meaningfulPublicApi();
    }
}
87
répondu Brice 2011-10-18 08:31:20

une solution générique qui fonctionnera avec n'importe quel cadre de test ( si votre classe n'est pas - final ) est de créer manuellement votre propre maquette.

  1. changez votre méthode privée pour protected.
  2. dans votre classe d'essai étendre la classe
  3. outrepasser la méthode précédemment-privé pour retourner n'importe quelle constante que vous voulez

cela n'utilise aucun cadre donc son pas aussi élégant, mais ça marchera toujours: même sans PowerMock. Alternativement, vous pouvez utiliser Mockito pour faire les étapes #2 et #3 pour vous, si vous avez déjà fait l'étape #1.

pour vous moquer directement d'une méthode privée, vous aurez besoin D'utiliser PowerMock comme indiqué dans le autre réponse .

19
répondu ArtB 2017-05-23 11:54:43

je connais un moyen de ny qui vous pouvez vous appeler en privé, la fonction de test dans mockito

@Test
    public  void  commandEndHandlerTest() throws  Exception
    {
        Method retryClientDetail_privateMethod =yourclass.class.getDeclaredMethod("Your_function_name",null);
        retryClientDetail_privateMethod.setAccessible(true);
        retryClientDetail_privateMethod.invoke(yourclass.class, null);
    }
1
répondu Arun Yadav 2017-08-24 08:21:08

pour une raison quelconque, la réponse de Brice ne fonctionne pas pour moi. J'ai pu la manipuler un peu pour la faire marcher. C'est peut-être parce que J'ai une nouvelle version de PowerMock. Je suis en utilisant 1.6.5.

import java.util.Random;

public class CodeWithPrivateMethod {

    public void meaningfulPublicApi() {
        if (doTheGamble("Whatever", 1 << 3)) {
            throw new RuntimeException("boom");
        }
    }

    private boolean doTheGamble(String whatever, int binary) {
        Random random = new Random(System.nanoTime());
        boolean gamble = random.nextBoolean();
        return gamble;
    }
}

la classe d'essai est la suivante:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.doReturn;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {
    private CodeWithPrivateMethod classToTest;

    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        classToTest = PowerMockito.spy(classToTest);

        doReturn(true).when(classToTest, "doTheGamble", anyString(), anyInt());

        classToTest.meaningfulPublicApi();
    }
}
1
répondu gaoagong 2018-04-06 16:26:05