我有类似的东西

private static final CustomObject ObjectA = new CustomObject();

    @Mock
    Foo1 foo1;

    @Mock
    Foo2 Foo2 = new Foo2(ObjectA);

    @Mock
    Foo3 foo3;

    @InjectMocks
    ContainerClass container;

我想在将ObjectA注入容器之前用ObjectA初始化Foo2。上面的代码不起作用。

编辑:我试图模拟Foo2,但有一个Foo2的内部对象,我想用一个真实的对象进行初始化,因此当我调用Foo2的方法时,该内部对象用于根据值给我提供我需要的结果在施工期间提供。

最佳答案

上面的代码不起作用。

1)@InjectMocks使用了很多“魔术”,并且不一定是设置被测对象的模拟的最清晰和可调试的方法。
在幕后,它尝试了多种操作:构造函数注入,属性设置器注入,字段注入。
但是,如果注入失败,则不会报告失败:

如果以下任何策略失败,则Mockito将不会报告
失败;也就是说,您将必须自己提供依赖项。

或者,您可以如此显式设置被测对象的依赖关系。

2)注意但重要的一点:用小写字母作为第一个字母来命名变量。用类名命名它们是不可读和常规的。

3)这没有道理:

@Mock
Foo2 Foo2 = new Foo2(ObjectA);

实例化Foo2,然后将其替换为Mockito模拟。
模拟Foo2行为,但让其ObjectA依赖关系成为非模拟对象并不是真正的逻辑。
这样,您不会真正模拟被测对象的依赖关系,因为您的调用模式是:

被测对象->模拟dep1->真实对象dep2

在这种情况下,编写集成测试(不带模拟)更加有意义。

在对ContainerClass进行单元测试时,您将仅测试ContainerClass行为。
您想要获得结果的ObjectA方法应该是对Foo2ObjectA调用,您可以在测试中模拟对Foo2的调用。
请注意,如果模拟其调用者的方法,则无需模拟ObjectA

这是一个例子:
public class Foo2{

    private ObjectA objectA;

    public Foo2(ObjectA objectA){
       this.objectA = objectA;
    }

    public Bar callObjectA(){
         return objectA.foo();
    }
}

您需要在此处模拟的是callToObjectA()
@Mock
Foo1 foo1;

@Mock
Foo2 foo2;

@Test
public void myMethod(){
   ContainerClass container = new ContainerClass(foo1, foo2);
   Bar mockedBar = new Bar(....);
   Mockito.when(foo2.callObjectA()).thenReturn(mockedBar);
   // invoke the method under test
   container.myMethod();
   // assertions ...
}

10-01 09:37
查看更多