使用Guice,如何将单元测试中的模拟对象注入到被测试的类中

时间:2017-12-21 13:31:59

标签: java dependency-injection mockito guice

请考虑以下代码:

@Singleton
public class MyServiceImpl {
    public int doSomething() {
        return 5;
    }
}

@ImplementedBy(MyServiceImpl.class)
public interface MyService {
    public int doSomething();
}

public class MyCommand {
    @Inject private MyService service;

    public boolean executeSomething() {
        return service.doSomething() > 0;
    }
}

public class MyCommandTest {
    @InjectMocks MyServiceImpl serviceMock;
    private MyCommand command;

    @Before public void beforeEach() {
        MockitoAnnotations.initMocks(this);
        command = new MyCommand();
        when(serviceMock.doSomething()).thenReturn(-1); // <- Error here
    }

    @Test public void mockInjected() {
        boolean result = command.executeSomething();
        verify(serviceMock).doSomething();
        assertThat(result, equalTo(false));
    }
}

当我尝试在我的模拟实现对象上存根doSomething()方法时,我的测试正在崩溃。我收到错误:

  

org.mockito.exceptions.misusing.MissingMethodInvocationException:   when()需要一个参数,该参数必须是模拟&#39;上的方法调用。   例如:       当(mock.getArticles())thenReturn(文章);

     

此外,此错误可能会显示,因为:   1.你存在以下任何一个:final / private / equals()/ hashCode()方法。这些方法无法进行存根/验证。嘲弄方法   不支持在非公共父类上声明。   2.在()内部,你不会在模拟上调用方法,而是在其他对象上调用方法。

我是Guice的依赖注入的新手,我不知道为什么我不能以这种方式模拟实现对象?

1 个答案:

答案 0 :(得分:5)

没有CDI的测试

一个简单的解决方案是将CDI与Constructor Injection相结合,并忘记Guice进行测试:

public class MyCommand {
    private final MyService service;

    @Inject
    public MyCommand(MyService service) {
        this.service = service;
    }

    public boolean executeSomething() {
        return service.doSomething() > 0;
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyCommandTest {
    @Mock
    MyServiceImpl serviceMock;
    private MyCommand command;

    @Before public void beforeEach() {
        MockitoAnnotations.initMocks(this);
        when(serviceMock.doSomething()).thenReturn(-1); // <- Error here

        // inject without Guice
        command = new MyCommand(serviceMock);
    }
}

使用Mockito进行CDI测试

否则,如果您不喜欢构造函数注入,则测试代码应如下所示:

@RunWith(MockitoJUnitRunner.class)
public class MyCommandTest {
    @Mock
    MyServiceImpl serviceMock;
    @InjectMocks 
    private MyCommand command;

    @Before 
    public void beforeEach() {
        MockitoAnnotations.initMocks(this);
        command = new MyCommand();
        when(serviceMock.doSomething()).thenReturn(-1); // <- Error here
    }
}