PowerMock + Mockito VS Mockito 单独

2022-01-14 00:00:00 mocking mockito java powermock

谁能总结一下,在 Mockito 之上添加 PowerMock 的具体功能是什么?

Can anyone please summarize, what exactly features gives you adding PowerMock on top of the Mockito?

到目前为止,我已经找到了这些:

So far I've found these:

  • 模拟静态、最终和私有方法
  • 移除静态初始化器
  • 允许在没有依赖注入的情况下进行模拟 - 我不清楚这一点.你能详细说明一下吗?

它是否添加了其他内容?你能概括几行吗?

Does it add anything else? Can you please sum up in several lines?

在使用 PowerMock 时我是否需要牺牲一些东西?

And do I need to sacrifice something when using PowerMock?

推荐答案

我不知道其他好处,但我想解决您的 2 个子问题(这对于评论来说太长了):

I don't know of other benefits offhand, but I want to address 2 of your sub-questions (and this is way too long for a comment):

允许在没有依赖注入的情况下进行模拟 - 我不清楚这一点.能详细点吗?

allow mocking without dependency injection - this one isn't clear to me. Can you elaborate?

我认为这来自 Motivation wiki 页面,他们在其中描述了一种将代码重构为不调用静态方法使其可测试.对于我认为他们正在处理的具体示例,假设您有这段代码,并且您想测试模拟静态方法行为的方法,而不使用 powermock:

I think this came from the Motivation wiki page where they describe a way of refactoring code to not invoke static methods to make it testable. For a concrete example of what I think they're getting at, let's say you have this code and you want to test the method mocking the behaviour of the static method, without using powermock:

public class MyClass {
     public void doGetString() {
         ...
         OtherClass.getString(); //It's complex and scary and needs mocking!
         ...
     }
}

一种解决方案是将静态调用拉到它自己的对象中,然后注入一个可以在测试时模拟的对象.例如,在不使用其他框架的情况下,这可能如下所示:

One solution, would be to pull the static invocation into its own object, then inject an object that can be mocked come test time. For example, without using other frameworks, this could look like:

public class MyClass {
     public static class StringGetter {
         public getString() {
             return OtherClass.getString();                 
         }
     }

     private final StringGetter getter;

     //Existing Constructor
     public MyClass() {
         this(new StringGetter());
     }

     //DI Constructor
     MyClass(StringGetter getter) {
         this.getter = getter;
     }

     public void doGetString() {
         ...
         getter.getString();
         ...
     }
}

我已经将我的方法的行为与静态调用的行为分开,并且可以在测试时使用 DI 构造函数轻松地注入模拟.当然,使用 powermock 我可以在适当的位置模拟静态方法,然后使用它运行.

I've seperated the behaviour of my method from the behaviour of the static invocation, and can use the DI constructor to inject mocks easily at test time. Of course with powermock I could just mock the static method in place, and run with it.

在使用 PowerMock 时我是否需要牺牲一些东西?

And do I need to sacrifice something when using PowerMock?

物理上不,但我会说哲学上是:).以下是我的观点,我试图给出很好的理由,但当然它们是观点,所以请持保留态度:

Physically no, but I'd say philosophically yes :). The below are my opinions, and I try to give good reasons behind them, but of course they are opinions so take them with a grain of salt:

PowerMock 发生的潜在可怕的事情是,为了完成模拟私有和静态方法的壮举,它们使用自定义类加载器(在生产运行时不应存在)并更改字节码你的课.可以说,在大多数情况下,这对于绝大多数类来说都无关紧要,但如果你考虑一下,如果字节码发生了变化,并且某些副作用不再存在,那么你实际上是在根据你的现有的类.是的,这是一个非常学术的论点.

The potentially scary thing that is happening with PowerMock is that in order to accomplish the feats of mocking private and static methods, they are using a custom class loader (which shouldn't be present at runtime in production) and changing the bytecode of your classes. Arguably, this should not matter with the vast majority of classes most of the time, but if you think about it, if the bytecode has changed, and certain side effects are no longer present, you're effectively testing different Classes albiet based upon your existing Classes. Yes this is a very academic argument.

通过不使用 PowerMock 的良好综合集成和更高级别的测试,您可以在一定程度上缓解第一个论点.通过这种方式,即使您的单元测试使用的是 PowerMock,您也可以对对象的行为更有信心.

You can somewhat mitigate this first argument by having good comprehensive integration and higher level tests that don't use PowerMock. In this way you can be more confident in the behaviours of your objects even if your unit tests are using PowerMock.

我反对 PowerMock 的另一个论点是,它几乎太容易成为拐杖.我同意 PowerMock 可以帮助测试使用遗留代码和您无法控制的其他代码的代码.但是我认为,当您可以控制需要模拟的类时,您应该避免使用它.如果您编写一个带有私有方法或静态方法的类,您需要显式地模拟以测试其他方法,我的直觉会说这个方法可能做得太多,应该重构和分解.PowerMock 已经在项目中可用,您可能会想模拟它并继续前进,这将减轻应该鼓励您重构相同的痛苦.是的,有时由于各种技术和非技术限制,这是不可能的,但解决痛点而不是避免它们是件好事:)

The other argument I have against PowerMock, is that it could almost too easily become a crutch. I agree that PowerMock can help with testing code that uses legacy code and other code that you do not have control over. However I would argue that when you have control over the classes that you need to mock, you should avoid its use. If you write a class with a private method or static method that you need to explicitly mock in order to test other methods, my gut instinct would say that this method may be doing too much and should be refactored and broken up. Having PowerMock already available in a project, you may be tempted to just mock it and move on, which would mitigate the pain that should encourage you to refactor the same. Yes there are sometimes due to various technical and non-technical constraints this is not possible, but it's good to solve pain points instead of avoid them :)

相关文章