【问题标题】:Are there any ways to mock static methods using mockito? [duplicate]有什么方法可以使用 mockito 来模拟静态方法? [复制]
【发布时间】:2015-11-03 22:49:36
【问题描述】:

我想为我的更改编写测试,但遇到了问题 - 更改是在静态方法中进行的。 代码是这样的

class GlobalData {
static boolean doSomething(...){...}
static xxx A() {...}
static yyy B() {...}
static void C() {
xxx a = A();
yyy b = B();

if (doSomething(a, b))
{
   a.xyz(b,42);
   ... my coode i want to test....
}
}

我想要的是模拟方法 A 和 B 以及 doSomething 以及方法 C 中使用的所有这些静态方法,但目前我找不到任何方法来做到这一点。你现在有吗?

【问题讨论】:

    标签: java unit-testing static mockito


    【解决方案1】:

    因为你不能覆盖静态方法,所以你不能在 Mockito 中模拟它们。

    【讨论】:

    • 不是单独使用 mockito,而是使用 Powermockito,您可以:codeproject.com/Articles/806508/…
    • OP 没有询问 Powermockito。所以...我坚持我的答案。
    • 您可以使用 PowerMockito。
    • 确实如此,但是,除了准确回答问题之外,本网站的目的还在于尽力提供帮助。如果我知道你知道 Powermockito,我什至会觉得你的回答有点粗鲁。如果您不想提及 Powermockito,因为您认为需要 Powermockito 意味着糟糕的设计(我经常同意这一点),那么您也应该说明这一点。
    【解决方案2】:

    你应该/可以使用单例模式。

    基本上所有的静态方法都会调用一个执行实际逻辑的内部私有对象(称为实例)。

    如果你这样做,你可以提供一个受保护的静态方法setInstance。在测试期间,您创建了一个模拟的 instance 并将其设置为静态类。

    这是可行的,但它不是最优雅的解决方案,但静态调用一开始就不是那么优雅。我正在回答,因为没有办法重构整个代码库(例如使用 Dependency Injection

    例如:

    class GlobalData {
        //private object that does all the actual logic
        private static GlobalData instance = new GlobalData();
    
        //constructor is private so no one can call it
        private GlobalData() {
    
        }
    
        //delegate the static call to the internal instance
        static boolean doSomething(...){ return instance._doSomething(); }
    
        //use underscore to keep similar name but avoid ambiguous call
        private boolean _doSomething(...){ ... }
    
        //same here
        static xxx A() { return instance._A(); }
        private xxx _A() {...}
    
        //this is not public, so must be called from the same package
        //since the constructor is private, no one will be able to create a GlobalData
        //except for mockito
        static void setInstance(GlobalData instance) {
            GlobalData.instance = instance;
        }
    }
    

    然后在你的测试中(应该在同一个包中):

    GlobalData instanceMocked = mock(GlobalData.class);
    //we mock the methods with underscore, as they are the instance methods, and
    //not the class methods
    when(instanceMocked._A()).thenReturn(whatever);
    when(instanceMocked._doSomething()).thenReturn(whatever);
    GlobalData.setInstance(instanceMocked);
    

    这只需要在您正在查看的类中进行一次小的重构,而不涉及项目的其余部分,同时实现您想要的。

    【讨论】:

    • 我过去使用过这种方法,它确实有效。它存在一些问题,但它比静态方法方法更容易进行单元测试。
    • 没错。不要滥用它,也不要认为它是一种很好的做法
    • 这种方法的另一点。虽然您可以使用 PowerMockito 模拟静态方法,但如果弄乱了我们的 JaCoCo 报告。 PowerMockito 所做的字节码操作破坏了 JaCoCo 的字节码操作。我敢肯定任何其他代码覆盖工具也是如此。
    • 问题是,当你从事真正的工作时,总会有很多你最好不要碰的遗产。这就是为什么我不能使用单例
    【解决方案3】:

    考虑使用 powerMock。它在 Mockito 上有一个扩展名为“powerMockito”。它还使您能够模拟静态方法。 https://github.com/jayway/powermock/wiki/MockitoUsage

    【讨论】:

      猜你喜欢
      • 2020-08-23
      • 2014-08-30
      • 2014-02-02
      • 2022-01-11
      相关资源
      最近更新 更多