Mockito的局限性

时间:2016-08-11 14:44:39

标签: java unit-testing mocking mockito

我知道Mockito并不支持模拟局部变量,静态方法和私有方法。有没有办法解决它。

就像私有方法从private更改方法一样,或者我们可以将其更改为受保护的接口,以便我们可以编写测试脚本。那么对于静态方法和局部变量我们有这样的东西。

https://github.com/mockito/mockito/wiki/FAQ说Mockito的局限性。任何Mockito大师都可以让我,如果它有任何其他限制,如何克服它们我的意思是重构。谢谢。

2 个答案:

答案 0 :(得分:0)

为了帮助理解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

答案 1 :(得分:-1)

避免Mockito限制的最佳方法是不要坚持编写隔离单元测试。

与某些人的想法相反,单元测试不需要与被测单元的依赖关系分开运行。正如described by Martin Fowler(和Kent Beck所做的那样,"父亲" TDD),单元测试可以是'社交'和#34; (没有嘲笑依赖)或"孤独" (使用模拟依赖项)。

因此,避免这些模拟工具限制的一种方法是简单地不依赖它们。您可以通过撰写" sociable"单元测试,或者(像我一样)全力以赴地编写集成测试。

另一个"解决方案"提到的是重构被测试的代码以解决模拟限制,或者设计用于模拟" (正如杰夫鲍曼所说)。 我希望大多数开发人员意识到这是一个糟糕的解决方案,因为它通常需要为SUT增加额外的复杂性,只是为了弥补特定模拟库中的任意限制。 考虑增加private方法的可访问性的情况,以便您可以直接测试它或模拟它。好吧,如果你觉得可以接受,你真的关心代码质量吗?如果您不在乎,那么为什么还要为自动开发人员测试而烦恼呢?