在 Mockito 中模拟对象创建的不同方式?

Different ways of mocking object creation in Mockito?

我看到了几种不同的模拟对象的方法。这种使用 InjectMocks 的方法与此处显示的方法之间到底有什么区别:https://github.com/mockito/mockito/wiki/Mocking-Object-Creation?

@ExtendWith(MockitoExtension.class)
public class MyTest() {
    @Mock ClassB uut;
    @InjectMocks ClassA cA;
    @Test
    public TestOne() {
        ...
    }
}

哪里

public class ClassA() {
    public ClassA() {
        ClassB temp = new ClassB();
    }
}

与此处显示的方法相比: https://github.com/mockito/mockito/wiki/Mocking-Object-Creation

到底有什么区别?

我认为这些方法之间没有本质区别。

InjectMocks 方法

实际上,要使其正常工作,您的 class 应该通过构造函数或 setter 接受依赖项(并且永远不能同时使用两者)。我会说这种方法使测试更容易,因为你在初始化阶段将你想要的任何东西注入你的 class 对象。

class Foo {
    private final Bar bar;

    public Foo(final Bar bar) {
        this.bar = bar;
    }  
}

如果这是我们的 class 测试,那么@InjectMock 所做的就是创建模拟,并执行以下操作:

Foo foo = new Foo(barMock);

除了可测试之外,想象一下如果 Bar 是一个接口,那么您可以在它的多个实现之间切换而无需实际接触 class 代码(理想情况下)。如果你有一个 DI 框架,那就更容易了。所以,基本上 class 的这种格式使其变得灵活。

使用单行方法创建对象

假设这是我们正在测试的 class。如您所见,我正在构造函数中初始化 属性 。从法律上讲,没有反射魔法,我不能在初始化期间或之后放置模拟 bar 变量。

class Foo {
    private final Bar bar;

    public Foo() {
        this.bar = new Bar();
    }  
}

Mockito 文档告诉您切换到单行方法或工厂助手的原因是:

  • Mockito 不能模拟构造函数,这意味着你不能在没有反射的情况下将模拟对象放在 bar 的位置,你只能在初始化之后这样做。一般来说,以我对测试的看法,应该尽量避免反射。
  • 单行函数看起来和构造函数一样干净,而且它们可以是描述性的(就像静态工厂方法)。

因此,当您将 class 切换为如下所示时:

class Foo {
    private final Bar bar;

    public Foo() {
        this.bar = makeBar();
    } 

    Bar makeBar() {
      return new Bar();
    } 
}

现在,你可以放置一个间谍,轻松地模拟 makeBar 方法。这同样适用于工厂方法。老实说,工厂方法对我来说看起来有点罗嗦,但我相信有时候它会派上用场。