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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38268929/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:09:56  来源:igfitidea点击:

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

javamockingmockitopowermockito

提问by Johan

In the usual mocking with @Mockand @InjectMocksannotations, the class under testing should be run with @RunWith(MockitoJUnitRunner.class).

在通常的模拟@Mock@InjectMocks注释中,被测类应该使用@RunWith(MockitoJUnitRunner.class).

@RunWith(MockitoJUnitRunner.class)
public class ReportServiceImplTestMockito {

     @Mock 
     private TaskService      mockTaskService;

     @InjectMocks 
     private ReportServiceImpl service;

         // Some tests
}

but in some example I am seeing @RunWith(PowerMockRunner.class)being used:

但在某些示例中,我看到有人@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
  }
}

could someone point it out whats the difference and when I want to use one instead of another?

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

采纳答案by GhostCat

On a first glance, the answer is simply: well, there are several mocking frameworks out there, and there are different ways to use them.

乍一看,答案很简单:嗯,有几个模拟框架,并且有不同的使用方法。

The first example tells JUnit to use the "unit test runner" that the Mockito mocking framework provides. The second example uses the unit test runner from the PowerMock framework.

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

In order for things to make sense, you would also have different import statements, as both frameworks have differentimplementations for the @Mock annotation for example.

为了使事情有意义,您还将使用不同的导入语句,因为例如,两个框架对 @Mock 注释都有不同的实现。

( the main point of using these framework-specific test runners is that they take care of initializing all the fields with special framework-specific annotations ).

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

So: the difference here is simply that: the first example is written to use the Mockito framework, the second one uses PowerMock.

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

Now, which one of those to use?

现在,使用哪一个?

Answer: Mockito.

答案:莫基托。

Why? Somehow an ugly truth is: the PowerMock-one basically is a cry for help. It says "the class under test is badly designed, please fix it". Meaning: as a developer, you can write "easy to test" code, or "hard to test" code. Many people do the second: they write code that is hard to test. And then, PowerMock(ito) provides means to stilltest that code.

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

PowerMock(ito) gives you the ability to mock (thus control) calls to staticmethods, and to new(). To enable that, PowerMock(ito) manipulates the byte code of your code under test. That is perfectly fine for small code bases, but when you face millions of lines of production code, and thousands of unit tests, things are totally different.

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

I have seen many PowerMock tests fail for no apparent reason, to find out hours later ... that some "static" thing somewhere else was changed, and that somehow affect a different PowerMock static/new driven test case.

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

At some point, our team made a conscious decision: when you write new code, and you can only test that with PowerMock ... that isn't acceptable. Since then, we only created Mockito test cases, and not once since then we saw similar bizarre problems that bugged us with PowerMock.

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

The only acceptable reason to use PowerMock is when you want to test existing (maybe 3rd party) code that you do not want to modify. But of course, what is the point of testing such code? When you can't modify that code, why should tests fail all of a sudden?

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

回答by Phil Ninan

PowerMockallows you to mock static and private methods as well as final classes and more.

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

PowerMock is a framework that extends other mock libraries such as EasyMock with more powerful capabilities. PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.

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

There may be some code smellif you need to mock those types of components, butit may be useful. At some point you may be working in an outdated project that created static helper classesthat have dependencies that need to be mocked. If you have the ability to change the architecture, then fix your design! Otherwise, use the right technology for your tests.

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

If you dont need to mock static or private functions than you dont need to use PowerMock. PowerMock is a wrapper around other mocking frameworks.

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

回答by Sven

PowerMock should never be your first choice. If you just written a class, which is only testable with PowerMock you did something wrong. A class should have dependency injection or a constructor with dependencies, so the testing is facilitated and of course: don't try to use static methods as these are not mockable in regular frameworks (read:mockito).

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

From the other hand: if you have a big project and you want to add unit tests to it because the previous developer did not do it, PowerMock can be the only solution without totally refactoring everything. And in that perspective I prefer PowerMock above no tests at all.

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

PowerMock is dirty as it changes the bytecode and code coverage with JaCoCo (SonarQube coverage runner) does not work, but the IntelliJ code coverage runner does work with PowerMock.

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

When in one class one method can't be tested with Mockito I split the test: one test class with Mockito and one test class with PowerMock. This will keep your code-coverage better in SonarQube.

当在一类中无法使用 Mockito 测试一种方法时,我将测试拆分:一个测试类使用 Mockito,一个测试类使用 PowerMock。这将使您在 SonarQube 中保持更好的代码覆盖率。

public class ClassToTest {

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

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

Then I have one class to test the first method:

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

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

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

And one with PowerMock:

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