Используя 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 () требует аргумент, который должен быть "вызовом метода для макета". Например: when (mock.getArticles ()). ThenReturn (Articles);

Кроме того, эта ошибка может появиться, потому что: 1. вы заглушаете любой из методов: final/private/equals()/hashCode(). Эти методы не могут быть проверены. Методы насмешек, объявленные в закрытых родительских классах, не поддерживаются. 2. внутри when () вы вызываете не метод на макете, а на каком-то другом объекте.

Я новичок в внедрении зависимостей через Guice, и я не уверен, почему я не могу издеваться над объектом реализации таким образом?

1 ответ

Решение

Тест без 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);
    }
}

Тест с Мокито, делающим CDI

Иначе, если вам не нравится Constructor Injection, тестовый код должен выглядеть так:

@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
    }
}
Другие вопросы по тегам