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

时间:2016-07-08 14:17:41

标签: java mocking mockito powermockito

在使用@Mock@InjectMocks注释的常规模拟中,正在测试的类应该使用@RunWith(MockitoJUnitRunner.class)运行。

@RunWith(MockitoJUnitRunner.class)
public class ReportServiceImplTestMockito {

     @Mock 
     private TaskService      mockTaskService;

     @InjectMocks 
     private ReportServiceImpl service;

         // Some tests
}

但在某些例子中我看到@RunWith(PowerMockRunner.class)正在使用:

@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
  }
}

有人可以指出它的差异是什么,当我想用​​一个而不是另一个时?

3 个答案:

答案 0 :(得分:20)

乍一看,答案很简单:好吧,有几个模拟框架,并且有不同的方法可以使用它们。

第一个例子告诉JUnit使用Mockito模拟框架提供的“单元测试运行器”。第二个示例使用PowerMock框架中的单元测试运行器。

为了使事情有意义,你也会有不同的import语句,因为例如两个框架都有不同的实现@Mock注释。

(使用这些特定于框架的测试运行程序的要点是它们负责使用特殊的特定于框架的注释初始化所有字段。)

所以:这里的区别仅仅是:第一个例子是使用Mockito框架编写的,第二个例子是使用PowerMock。

现在,使用哪一个?

答案:Mockito。

为什么呢?不知何故,一个丑陋的事实是:PowerMock-one基本上是一个求助的呼声。它说“被测试的课程设计很糟糕,请修理它”。含义:作为开发人员,您可以编写“易于测试”的代码或“难以测试”的代码。许多人做第二个:他们编写难以测试的代码。然后,PowerMock(ito)提供了仍然测试该代码的方法。

PowerMock(ito)使您能够模拟(从而控制)对静态方法和new()的调用。为此,PowerMock(ito)操纵代码的字节代码。这对于小代码库来说非常好,但是当你面对数百万行代码和数千个单元测试时,事情就完全不同了。

我已经看到很多PowerMock测试失败没有明显的原因,几个小时之后发现...其他地方的某些“静态”事情发生了变化,并且不知何故影响了不同的PowerMock静态/新驱动的测试用例。

在某些时候,我们的团队做出了一个有意识的决定:当您编写新代码时,您只能使用PowerMock进行测试......这是不可接受的。从那以后,我们只创建了Mockito测试用例,从那时起我们就没有一次看到类似奇怪的问题,这些问题让我们对PowerMock感到困扰。

使用PowerMock的唯一可接受的原因是您想要测试不想修改的现有(可能是第三方)代码。但当然,测试此类代码的重点是什么?当您无法修改该代码时,为什么测试会突然失败?

答案 1 :(得分:1)

PowerMock永远不应该是您的首选。如果您刚刚编写了一个只能通过PowerMock测试的类,那么您做错了。类应该具有依赖注入或具有依赖性的构造函数,因此测试是便利的,当然:不要尝试使用静态方法,因为这些方法在常规框架中不可模仿(读取:mockito)。

另一方面:如果你有一个大项目,并且你想为它添加单元测试,因为之前的开发人员没有这样做,PowerMock可能是唯一没有完全重构所有内容的解决方案。从那个角度来看,我更喜欢PowerMock而不是任何测试

PowerMock是脏的,因为它改变了字节码和JaCoCo(SonarQube coverage runner)的代码覆盖率不起作用,但IntelliJ代码覆盖运行器可以与PowerMock一起使用。

当在一个班级中,一个方法无法使用Mockito进行测试时,我将测试分开:一个测试类使用Mockito,一个测试类使用PowerMock。这将使您的代码覆盖率在SonarQube中更好。

public class ClassToTest {

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

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

然后我有一个类来测试第一个方法:

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

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

还有一个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());
   }
}

答案 2 :(得分:0)

PowerMock允许您模拟静态和私有方法以及最终类等。

  

PowerMock是一个扩展其他模拟库的框架,例如   EasyMock具有更强大的功能。 PowerMock使用自定义   类加载器和字节码操作,以实现静态模拟   方法,构造函数,最终类和方法,私有方法,   删除静态初始化程序等。

如果您需要模拟这些类型的组件,可能会有一些代码异味可能会有用。在某些时候,您可能正在处理一个过时的项目,该项目创建了静态帮助程序类,其中需要模拟的依赖项。如果您有能力更改架构,那么修复您的设计!否则,使用正确的技术进行测试。

如果您不需要模拟静态或私有函数,则不需要使用PowerMock。 PowerMock是其他模拟框架的包装器。