web-dev-qa-db-fra.com

@RunWith (PowerMockRunner.class) vs @RunWith (MockitoJUnitRunner.class)

Dans les moqueries habituelles avec les annotations @Mock et @InjectMocks, la classe à tester devrait être exécutée avec @RunWith(MockitoJUnitRunner.class)

@RunWith(MockitoJUnitRunner.class)
public class ReportServiceImplTestMockito {

     @Mock 
     private TaskService      mockTaskService;

     @InjectMocks 
     private ReportServiceImpl service;

         // Some tests
}

mais dans certains exemples, je vois que @RunWith(PowerMockRunner.class) est utilisé:

@RunWith(PowerMockRunner.class)
public class Tests {
  @Mock
  private ISomething mockedSomething;

  @Test
  public void test1() {
    // Is the value of mockedSomething here
  }

  @Test
  public void test2() {
    // Is a new value of mockedSomething here
  }
}

quelqu'un pourrait-il indiquer quelle est la différence et quand je veux utiliser l'un au lieu d'un autre?

14
Johan

À première vue, la réponse est simplement: eh bien, il existe plusieurs cadres moqueurs.

Mais la triste vérité est que: le PowerMock-one est essentiellement un appel à l’aide. Il est écrit "la classe sous test est mauvaise, corrigez-la, s'il vous plaît".

Sérieusement; PowerMock vous permet de tester du code qui ne peut pas être testé avec d’autres frameworks moqueurs: il prend vos classes de production (donc le code octet provenant de votre source) et manipule celles-ci afin de permettre le moquage statique} méthodes ou finale classes/méthodes. Cela peut ne pas sembler trop grave, mais croyez-moi, c’est vrai.

Tout d’abord, cela signifie que PowerMock ne teste pas les classes vos, mais les classes que PowerMock manipulées. Ensuite: cela tue (plus ou moins complètement) votre capacité à utiliser des outils de couverture. 

Et le pire de tout: soyez prêt pour des échecs bizarres, que vous ne comprenez pas, que vous pouvez déboguer pendant des heures, pour ne jamais rien trouver de mal avec votre code. Surtout quand vous travaillez déjà avec d'autres frameworks qui manipulent des octets.

Donc, en substance: parfois, une conception était mise en œuvre de manière à rendre impossible le test. Ensuite, certaines personnes décident d’utiliser PowerMock afin de résoudre ces problèmes tout en permettant les tests. 

Mais à mes yeux: vous ne devriez pas vous tourner vers PowerMock, mais plutôt vous devriez {changer} votre conception et résoudre les problèmes qui vous poussent à demander PowerMock.

La seule raison acceptable d'utiliser PowerMock est lorsque vous souhaitez tester le code existant (peut-être une tierce partie) que vous ne souhaitez pas modifier. Mais bien sûr, à quoi sert-il de tester un tel code? Quand vous ne pouvez pas modifier ce code, pourquoi les tests devraient-ils échouer tout d'un coup? 

20
GhostCat

PowerMock ne devrait jamais être votre premier choix. Si vous venez d'écrire un cours, qui n'est testable qu'avec PowerMock, vous avez commis une erreur. Une classe doit avoir une injection de dépendance ou un constructeur avec des dépendances, ainsi le test est facilité et bien sûr: n'essayez pas d'utiliser des méthodes statiques car elles ne sont pas fictives dans les frameworks classiques (lire: mockito).

D'autre part: si vous avez un gros projet et que vous souhaitez y ajouter des tests unitaires, car le développeur précédent ne l'a pas fait, PowerMock peut être la seule solution sans tout refactoriser totalement. Et dans cette perspective je préfère PowerMock à pas de test du tout

PowerMock est sale car il change le bytecode et la couverture de code avec JaCoCo (programme de couverture de SonarQube) ne fonctionne pas, mais le programme de couverture de code IntelliJ fonctionne avec PowerMock. 

Quand dans une classe, une méthode ne peut pas être testée avec Mockito, je scissionne le test: une classe de test avec Mockito et une classe de test avec PowerMock. Cela maintiendra votre couverture de code mieux dans SonarQube.

public class ClassToTest {

    public void testableMethod() {
        /* Do something */
    }

    public String methodWithStaticCall() {
        return MyTest.staticMethod();
    }
}

Ensuite, j'ai une classe pour tester la première méthode:

@RunWith(MockitoJUnitRunner.class)
public class testClassToTest() {
   private sut = new ClassToTest();

   @Test
   public testMethod() {
       sut.testableMethod();
   }
}

Et un avec PowerMock:

@RunWith(PowerMockJUnitRunner.class)
@PrepareForTest({MyTest.class, ClassToTest.class})
public class testClassToTestPM() {
   private sut = new ClassToTest();

   @Before
   public void before() {
       mockStatic(MyTest.class);
   }

   @Test
   public testMethod() {
       mockStatic(MyTest.class);
       when(MyTest.staticMethod()).thenReturn("test");
       assertEquals("test", sut.methodWithStaticCall());
   }
}
1
Sven

PowerMock vous permet de vous moquer des méthodes statiques et privées ainsi que des classes finales et plus. 

PowerMock est un framework qui étend d'autres bibliothèques fictives telles que EasyMock avec des capacités plus puissantes. PowerMock utilise un personnalisé Le chargeur de classe et la manipulation de bytecode pour permettre de se moquer de static méthodes, constructeurs, classes finales et méthodes, méthodes privées, suppression des initialiseurs statiques et plus.

Il peut y avoir quelques odeur de code} si vous devez vous moquer de ces types de composants, mais il peut être utile. Il est possible que vous travailliez dans un projet obsolète ayant créé classes auxiliaires statiques avec dépendances à simuler. Si vous avez la possibilité de changer d'architecture, alors corrigez votre conception! Sinon, utilisez la bonne technologie pour vos tests.

Si vous n'avez pas besoin de vous moquer de fonctions statiques ou privées, vous n'avez pas besoin d'utiliser PowerMock. PowerMock est un wrapper autour d'autres frameworks moqueurs. 

0
Phil Ninan