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

新手上路,请多包涵

在通常使用 @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
  }
}

有人可以指出有什么区别以及我什么时候想使用一个而不是另一个吗?

原文由 Johan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

乍一看,答案很简单:好吧,有几种模拟框架,而且有不同的使用方法。

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

为了使事情有意义,您还需要不同的 import 语句,因为两个框架都有 不同 的 @Mock 注释实现。

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

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

现在,使用其中的哪一个?

答:莫基托。

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

PowerMock(ito) 使您能够模拟(从而控制)对 静态 方法和 new() 的调用。为了实现这一点,PowerMock(ito) 操纵 被测 代码的字节码。这对于小型代码库来说完全没问题,但是当您面对数百万行生产代码和数千个单元测试时,情况就完全不同了。

我已经看到许多 PowerMock 测试无缘无故失败,数小时后才发现……其他地方的一些“静态”东西被改变了,并且以某种方式影响了不同的 PowerMock 静态/新驱动测试用例。

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

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

原文由 GhostCat 发布,翻译遵循 CC BY-SA 4.0 许可协议

PowerMock 绝不应该是您的首选。如果您只是编写了一个只能使用 PowerMock 进行测试的类,那么您做错了什么。一个类应该具有依赖注入或具有依赖性的构造函数,以便于测试,当然:不要尝试使用静态方法,因为它们在常规框架中不可模拟(阅读:mockito)。

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

PowerMock 很脏,因为它更改了字节码,并且 JaCoCo(SonarQube 覆盖率运行器)的代码覆盖率不起作用,但 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());
   }
}

原文由 Sven 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题