【问题标题】:How to mock internal members without initializing class如何在不初始化类的情况下模拟内部成员
【发布时间】:2016-01-02 12:04:28
【问题描述】:

我想为以下类编写单元测试:

public class Target() {

    private final Member member = new Member();

    public Target() {
    } 

}

我想用 Member 的模拟实例来初始化这个 Target 类,因为在测试期间实例化 Member 是不可行的。任何框架都可以做到这一点吗?

编辑:

我不想模拟 Target 类。我打算在初始化时模拟 Member 类。

Object method() {
    member.differentMethod();
    //Logic which I want to test
}

请建议如何模拟这个对成员类方法的调用。

【问题讨论】:

  • 是的,你的 easymock/mocito/powermock 框架。但是您只是对模拟框架感兴趣还是想测试 Target 类本身?
  • 我希望测试 Target 类。但是,每当我尝试初始化 Target() 时,我都会收到一个错误,因为它在内部调用 Member(),这需要设置我想要避免的资源负载。我知道如何使用带参数的构造函数来初始化带有模拟对象的类。但我不知道在这种情况下如何做到这一点。
  • 没有意义但模拟目标类,你将如何测试目标类本身?
  • 有些误会。我不想模拟 Target 类,而是其中的 Member 类。更新了描述。
  • 不使用这种隐式依赖和紧密绑定,而是将 Member 对象作为参数传递给构造函数(构造函数注入)。这样你就可以在你的单元测试中通过一个模拟的成员。

标签: java unit-testing testing mocking mockito


【解决方案1】:

要建立 Prim 的答案(赞成),只需给自己两个构造函数。

public class Target() {

  private final Member member;

  public Target() {
    this.member = new Member();
  }

  /** Testing constructor. Package-private visibility for tests in the same package. */
  Target(Member member) {
    this.member = member;
  }    
}

通过提供多个构造函数,您可以确保生产中的消费者根本不需要改变。这也是“测试代码污染生产”的一个不同案例:您的一个用例(特别是测试)需要成员的自定义实现,并且您正在提供最封装的访问以将该成员替换为规范'编。

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

【讨论】:

    【解决方案2】:

    您可以将constructor mockingPowermock 一起使用:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(Target.class)
    public class Test {
        @Test
        public void doSomething() throws Exception {
            Member mockMember = mock(Member.class);
            PowerMockito.whenNew(Member.class).thenReturn(mockMember);
            Target thisTargetWillHaveYourMockAsField = new Target();
            //Your test code
        }
    }
    

    【讨论】:

    • 这就是我要找的!非常适合我的情况。无需更改测试类设计。
    • 很高兴听到它有帮助。感谢您接受答案。铜。
    【解决方案3】:

    您应该将 Target 类使用的 Member 实例传递给 Target 类的构造函数。

    通过这样做,您可以在生产环境中使用您的成员类的实现,并在测试环境中使用另一个实现(可能为空)。

    最好和最优的解决方案是使用依赖倒置/注入原理

    【讨论】:

    • 是的,我知道这种方法。但是有没有办法在不改变 NoArgsConstructor 的情况下做到这一点?
    • 您可以在 Target 中不使用 args 构造函数,方法是实现一个提供程序类来委托创建成员实例,并根据生产或测试环境返回不同的实现
    • 好吧,我想我必须以某种方式改变 Target 类的设计方式以正确测试它。通过更改构造函数,或使用提供程序类或工厂来初始化成员。让我们看看是否有人提出了一个解决方案,而实际上不需要更改 Target 类。
    猜你喜欢
    • 2022-10-17
    • 2011-01-19
    • 2019-04-09
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 2022-08-17
    • 1970-01-01
    相关资源
    最近更新 更多