有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Mockito的java局限性

我知道Mockito不支持模拟局部变量、静态方法和私有方法。有没有办法绕过它

就像在私有方法的情况下,将方法从私有更改为私有就可以了,或者我们可以将其更改为受保护的接口,以便编写测试脚本。那么,对于静态方法和局部变量,我们有类似的东西吗

https://github.com/mockito/mockito/wiki/FAQ说Mockito的局限性。如果Mockito大师还有其他限制,以及如何克服这些限制,我指的是重构。多谢各位


共 (2) 个答案

  1. # 1 楼答案

    避免Mockito局限性的最好方法是不要坚持编写独立的单元测试

    与一些人的想法相反,单元测试不需要与被测试单元的依赖项隔离运行。作为described by Martin Fowler(正如TDD的“父亲”Kent Beck所实践的那样),单元测试可以是“社交的”(没有模仿依赖项)或“孤立的”(有模仿依赖项)

    因此,避免这些模仿工具限制的一种方法就是不依赖它们。您可以通过编写“社交”单元测试来实现这一点,或者(像我一样)全程编写集成测试

    提到的另一个“解决方案”是重构测试中的代码,以绕过模拟限制,或者“为模拟而设计”(正如Jeff Bowman所说)。 我希望大多数开发人员意识到这是一个糟糕的解决方案,因为它通常需要向SUT添加额外的复杂性,以弥补特定模拟库中的任意限制。 考虑增加^ {< CD1> }方法的可访问性的情况,这样您就可以直接测试它或模拟它。好吧,如果你觉得这是可以接受的,你真的关心代码质量吗?如果你不在乎,那为什么还要为自动化开发人员测试而烦恼呢

  2. # 2 楼答案

    为了帮助理解Mockito的局限性,了解Mockito为您做了什么是很重要的:Mockito为您传入的类创建了一个动态(基于代理的)子类<这意味着,就像您自己编写的子类一样,您将无法访问或控制私有字段和方法、静态方法和局部变量。没有解决办法

    您在评论中提到了PowerMock,它通过重写要模拟的类的字节码,或者重写使用要模拟的类的类的字节码,从而绕过了Mockito的一些限制。这允许PowerMock拦截不能通过多态性覆盖的调用,特别是privatestaticfinal字段。您也将无法访问局部变量

    相反,您最好的选择是重新构造类或方法,以便它确实能够提供您想要的控制。一般来说,您应该问“如果我创建了自己的子类,我是否能够做到这一点”,这个答案将有助于确定Mockito是否能够为您实现自动化

    (注意,下面我提到的是“为模仿而设计的”,但您真正做的是为依赖项的替代实现而设计;模拟只是这方面的一个例子,还有许多其他的测试双重功能,比如假的或内存中的实现。记住,并不是所有的测试都需要模拟或替换,以保持单元测试;只需确保您在测试中的依赖关系是快速的、确定的,并且经过良好测试。相反,对于速度慢、不确定、测试不好或尚未编写的组件,用假组件或模拟组件替换实现可能会提高测试质量和覆盖率。)

    public class NotDesignedForMocking {
      public int yourMethod() {
        Calculator calculator = new Calculator();  // impossible to mock!
        return calculator.calculate();
      }
    }
    

    一种技术是将依赖项作为方法参数传入

    public class DesignedForMockingViaMethodLevelDependencyInjection {
      public int yourMethod() {
        return yourMethod(new Calculator());
      }
    
      // Call this from tests instead; you can pass in a mock.
      int yourMethod(Calculator calculator) {
        return calculator.calculate();
      }
    }
    

    另一种是切换到完全依赖项注入:

    public class DesignedForMockingViaFullDependencyInjection {
      private final Calculator calculator;
    
      public DesignedForMockingViaFullDependencyInjection() {
        this(new Calculator());
      }
    
      // Create objects in your test with this, so you can pass in a mock Calculator.
      DesignedForMockingViaFullDependencyInjection(Calculator calculator) {
        this.calculator = calculator;
      }
    
      int yourMethod() {
        return calculator.calculate();
      }
    }
    

    最后,您可以创建一个可重写工厂方法,该方法引入Mockito基于子类的重写所需的多态性

    public class DesignedForMockingWithOverridableFactoryMethod {
      public int yourMethod() {
        Calculator calculator = createCalculator();
        return calculator.calculate();
      }
    
      // Create an anonymous override in your class, or use a Mockito spy to intercept
      // and override the behavior.
      protected Calculator createCalculator() {
        return new Calculator();
      }
    }
    

    另见:How to use Mockito when we cannot pass a mock object to an instance of a class