web-dev-qa-db-fra.com

Comment utiliser Mockito pour se moquer d'une méthode protégée?

J'utilise Mockito 1.9.5. Comment puis-je me moquer de ce qui revient d'une méthode protégée? J'ai cette méthode protégée…

protected JSONObject myMethod(final String param1, final String param2)
{
…
}

Cependant, lorsque j'essaie de faire cela dans JUnit:

    final MyService mymock = Mockito.mock(MyService.class, Mockito.CALLS_REAL_METHODS);        
    final String pararm1 = “param1”;
    Mockito.doReturn(myData).when(mymock).myMethod(param1, param2);

Sur la dernière ligne, je reçois une erreur de compilation «La méthode‘ myMethod ’n’est pas visible.» Comment utiliser Mockito pour se moquer des méthodes protégées? Je suis ouvert à la mise à niveau de ma version si cela répond à vos attentes.

16
Dave

Ce n'est pas un problème avec Mockito, mais avec le vieux Java clair. De là où vous appelez la méthode, vous n’avez pas de visibilité. C'est pourquoi il s'agit d'un problème de compilation plutôt que d'un problème d'exécution.

Quelques options:

  • déclarez votre test dans le même paquet que la classe fausse
  • changer la visibilité de la méthode si vous le pouvez
  • créez une classe locale (interne) qui étend la classe simulée, puis simulez cette classe locale. Puisque la classe serait locale, vous auriez une visibilité sur la méthode.
26
John B

En réponse à la demande d'échantillon de code de l'option 3 de la réponse de John B:

public class MyClass {
    protected String protectedMethod() {
        return "Can't touch this";
    }
    public String publicMethod() {
        return protectedMethod();
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    class MyClassMock extends MyClass {
        @Override
        public String protectedFunction() {
            return "You can see me now!";
        }
    }

    @Mock
    MyClassMock myClass = mock(MyClassMock.class);

    @Test
    public void myClassPublicFunctionTest() {
        when(myClass.publicFunction()).thenCallRealMethod();
        when(myClass.protectedFunction()).thenReturn("jk!");
    }
}
7
Nyefan

John B a raison, c'est parce que la méthode que vous essayez de tester est protégée, ce n'est pas un problème avec Mockito. 

Une autre option s'ajoutant à celles qu'il a énumérées serait d'utiliser la réflexion pour accéder à la méthode. Cela vous permettra d'éviter de changer la méthode que vous testez et du motif que vous utilisez pour écrire des tests et où vous stockez ces tests. J'ai dû le faire moi-même pour certains tests où je n'ai pas été autorisé à modifier la base de code existante, qui incluait un grand nombre de méthodes privées qui devaient être testées à l'unité.

Ces liens expliquent très bien Reflection et son utilisation. Je vais donc créer un lien vers eux plutôt que de les copier:

1
Seb

WhiteBox.invokeMethod () peut être pratique.

0
Smart Coder

Vous pouvez utiliser ReflectionTestUtils de Spring pour utiliser votre classe telle quelle et sans avoir besoin de la changer uniquement pour les tests ou de la placer dans une autre classe.

public class MyService {
    protected JSONObject myProtectedMethod(final String param1, final String param2) {
        return new JSONObject();
    }

    public JSONObject myPublicMethod(final String param1) {
        return new JSONObject();
    }
}

Et puis en test

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Mock
    private MyService myService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(myService.myPublicMethod(anyString())).thenReturn(mock(JSONObject.class));
        when(ReflectionTestUtils.invokeMethod(myService, "myProtectedMethod", anyString(), anyString())).thenReturn(mock(JSONObject.class));
    }

}
0
nicmon