【问题标题】:Patching Java classes with a mock implementation in a unit test在单元测试中使用模拟实现修补 Java 类
【发布时间】:2012-09-30 20:54:58
【问题描述】:

我有一个 A 类,它在内部从 B 类实例化一个对象。第二类有很多外部副作用,例如。它使用网络连接。

public class A {
  private B b;
  public A() {
    b = new B(); // 3rd party class that calls out externally (e.g. to a db)
  }
}

我想通过提供 B 类的模拟实现来对 A 类进行单元测试。我可以通过编写自己的类或使用 Mockito 和其他框架之类的东西轻松创建 B 的模拟版本,但是如何注入这个模拟实现到 A 类的代码中?

我想我可以在 A 类的构造函数中请求 B 类的实例,但这看起来很难看。没有人真正需要知道 A 级是如何开展业务的。

Python 有一个“模拟”库,允许您在测试期间的运行时“修补”函数。 Java有类似的吗?

【问题讨论】:

  • 根据我的经验,创建“模拟对象”的最简单方法是:1)创建一个具有相同类/文件名的新 .java 文件,2)复制/粘贴所有公共方法,3)添加“做某事”所需的最低限度,4)修改我的项目,以便构建将选择新的“模拟”类而不是“真实”类。恕我直言...
  • 一个常见的解决方案是“依赖注入”。基本上这意味着你避免做“b = new B();”在您的构造函数中精确地保持“可测试性”。相反,您总是拥有从外部提供的所需对象。这意味着就A 而言,使用真实对象或模拟对象没有区别。

标签: java unit-testing mocking


【解决方案1】:

在这种情况下,我通常有一个第二个包(默认)范围构造函数,它允许您传递一个模拟以进行测试。

public class A {
  private B b;

  /*
  *  Used by clients
  */
  public A() {
    this(new B());
  }

  /*
  * Used by unit test
  * 
  * @param b A mock implementation of B
  */
  A(B b) {
    this.b = b;
  }
}

【讨论】:

  • 我认为这可能是不使用 Spring 之类的最佳折衷方案。我将看看是否可以使用 DI 更正确地解决此问题。
【解决方案2】:

查看Mockito. 最终,根据您的设计,您需要使用反射将 B 的模拟实例放入 A。

【讨论】:

    【解决方案3】:

    使用 JMockit 模拟 API 可以轻松解决这个问题:

    public class ATest
    {
        @Test
        public void myTest(@Mocked B mockB)
        {
            // Record expectations on "mockB", if needed.
    
            new A().doSomethingUsingB();
    
            // Verify expectations on "mockB", if applicable.
        }
    }
    

    【讨论】:

    • 请问这个mock类B的构造函数?如果不是,那么这不是原始问题所要求的。
    • 是的,它会的。 @Mocked 类中的所有构造函数和方法(包括staticfinalprivate 等)都被模拟
    猜你喜欢
    • 2015-05-05
    • 2021-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    相关资源
    最近更新 更多