在使用@InjectMocks注入模拟对象内部之前初始化它

时间:2018-02-07 20:38:11

标签: java unit-testing dependency-injection mockito

我有类似

的东西
private static final CustomObject ObjectA = new CustomObject();

    @Mock
    Foo1 foo1;

    @Mock
    Foo2 Foo2 = new Foo2(ObjectA);

    @Mock
    Foo3 foo3;

    @InjectMocks
    ContainerClass container;

我想在将Object注入容器之前用ObjectA初始化Foo2。上面的代码无效。

编辑:我正在尝试模拟Foo2,但是有一个Foo2的内部对象,我想用真实对象进行初始化,所以当我调用Foo2的方法时,这个内部对象用于给我基于我需要的结果我在建造过程中提供的价值。

2 个答案:

答案 0 :(得分:1)

  

以上代码无效。

1)@InjectMocks使用了很多“魔法”,并且没有必要采用最清晰,可调试的方式来设置被测对象的模拟。
在引擎盖下,它尝试了多种方法:构造函数注入,属性设置器注入,现场注入 但如果它没有注入,那就不会报告失败:

  

如果以下任何策略失败,那么Mockito将不会报告   失败;即你必须自己提供依赖。

作为替代方案,您可以明确设置被测对象的依赖关系。

2)侧面但重要的注意事项:使用小写作为首字母命名变量。用类名命名它们是不可读和传统的。

3)这没有意义:

@Mock
Foo2 Foo2 = new Foo2(ObjectA);

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

  

受测对象 - > mock 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 ...
}

答案 1 :(得分:0)

尽管代码风格,但你遇到的问题是Foo2并不是真正的模拟,因为你明确地实例化它。如果您确实想要使用Foo2实例实例化的“真实”Object2实例,请考虑在@Spy上使用Foo2注释。然后,@InjectMocks注释应该按照您的预期进行。