Мокито не признает класс
Я пытался использовать Weld-Junit5 с издевательством над классом. Я издеваюсь над классом, потому что хочу знать, как часто он будет называться.
Но каждый раз, когда я пытаюсь использовать Mockito.verify(), этот издевательский класс выдает "NotAMockException".
Отладчик Intellij проверяет поле как: "Mock for MessageService, hashCode: XY"
Я уже пытался добавить свой тестовый класс в WeldInitiator, но он не хочет работать.
"MessageService" - это реальный класс, а не интерфейс (интерфейс также не будет работать)
@EnableWeld
class GameServiceTest {
@WeldSetup
public WeldInitiator weld = WeldInitiator.from(GameService.class, GameCache.class,
/** Some More **/,
GameServiceTest.class).build();
@Produces
@ApplicationScoped
public MessageService createMessageServiceMock() {
return mock(MessageService.class);
}
@Inject
private MessageService messageService;
@Inject
private GameService gameService;
@Test
void handleRunningGames() {
this.gameService.handleRunningGames(null, mock(Session.class));
// This will throw a org.mockito.exceptions.misusing.NotAMockException
Mockito.verify(messageService, Mockito.times(1)).writeMessage(any(), any());
}
}
Я ожидаю, что Injected MessageService - это настоящий макет, на котором я могу вызывать каждую функцию Mockito, но, похоже, это не так.
Что-то не так, или как это правильно сделать?
Я думаю, что я только что решил эту проблему:
private static final MessageService messageService = mock(MessageService.class);
@Produces
@ApplicationScoped
public MessageService createMessageServiceMock() {
return messageService;
}
2 ответа
Чтобы дать некоторое представление о том, как это работает, Weld позволяет Mockito создать нужный объект, а затем принимает его как контекстный экземпляр компонента.
Однако в CDI любой бин с нормальной областью действия должен иметь прокси-сервер, который передается вместо этого экземпляра. Так что ваш продюсер на самом деле делает (потому что это @ApplicationScoped
) - создать объект, сохранить его в контексте, а затем создать прокси-сервер и вместо него передать его. Прокси-сервер - это другой объект (делегат без состояния), который "знает", как получить ссылку на фактический экземпляр.
Так что происходит, что прокси вводится в поле, и вы проверяете объект прокси с Mockito.verify()
вызов. Очевидно, что прокси-сервер не является имитацией и поэтому не работает. Как предложил пользователь @second, Weld предлагает API для развертывания прокси и получения контекстного экземпляра. Я бы сказал, что API не "уродлив", это просто то, что пользователям в основном не нужно заботиться, но иногда вы не можете избежать этого.
Вы можете избежать использования прокси, используя некоторые из псевдоскопов, которые @Dependent
или CDI @Singleton
, При этом он должен работать так же хорошо, как и для тестов, замена приложения, ограниченного синглтоном, должна работать.
Что касается вашего обходного пути, я не вижу, как это решает что-либо - это в основном тот же производитель, и из-за области действия он будет вызываться только один раз, поэтому статическое поле не будет иметь значения (поскольку будет особый вызов mock творчество). Вы изменили что-то еще, чем это?
Как пользователь JUnit 5 + Weld-JUnit, я использую следующую схему. Причины объяснены в ответе Силиаруса.
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mock;
import ...
@EnableWeld
@ExtendWith(MockitoExtension.class) // (1)
class GameServiceTest {
@WeldSetup
public WeldInitiator weld = WeldInitiator.from(GameService.class, GameCache.class,
/** Some More **/,
GameServiceTest.class).build();
@Produces
@ApplicationScoped // (2)
@Mock // (3)
private MessageService messageServiceMock;
// @Inject // (4)
// private MessageService messageService;
@Inject
private GameService gameService;
@Test
void handleRunningGames() {
this.gameService.handleRunningGames(null, mock(Session.class));
// (5)
Mockito.verify(messageServiceMock, Mockito.times(1)).writeMessage(any(), any());
}
}
Пояснения:
- Я использую расширение Mockito для удобства
- Вам не нужно давать ему область применения
@Mock
аннотация обрабатываетсяMockitoExtension
, Опять же, это только для удобства, вы можете создать макет самостоятельно в методе продюсера.Вам НЕ нужно вводить фиктивный сервис; у тебя есть
messageServiceMock
! Внедренная вещь здесь будет прокси Weld, как объяснил Siliarus.Это забавно описать эту инъекцию немного больше: если боб
@ApplicationScoped
т. е. "с нормальной областью действия", CDI должен вводить прокси. Если вы используете этот прокси вместо фактического макета, вы получите исключение. Если вы последуете моему совету из (2) и пропустите@ApplicationScoped
бин будет зависеть от области видимости, а макет вводится напрямую. В этом случае вы можете использовать введенное поле, но зачем?- Используйте макет напрямую.