Guice, DI и Unit Tests in Play 2.4
Итак, я пытался понять это самостоятельно, используя документацию, но я никуда не денусь.
У меня есть простая настройка привязок DI в классе сервиса, который создает объект репозитория. Просто. Однако, когда я запускаю это в тестовом режиме, @Inject ничего не делает, и объект репозитория никогда не создается.
@Inject
TagRepository tagRepository;
Итак, в строке, где он используется, в тестовом режиме мы, конечно, получаем NullPointerException
tagRepository.tagExistsByName(tag);
Это впрыскивается в мой тест следующим образом:
[error] Test services.TagsServiceTest.testAddNewTag failed: java.lang.NullPointerException: null, took 0.097 sec
[error] at services.TagService.tagExists(TagService.java:27)
[error] at services.TagService.addNewTag(TagService.java:18)
[error] at services.TagsServiceTest.testAddNewTag(TagsServiceTest.java:29)
Мой вопрос: как мне настроить приложение для использования инжекторов Guice в тестовом режиме? У меня не было этой проблемы с моими контроллерами, потому что на них действительно делали запросы, настраивая полное приложение.
Одна вещь, которую я должен упомянуть, это то, что я использую провайдера для предоставления моего приложения для тестов. Должен ли я использовать построитель приложений Guice? Если да, то куда это? Игровые документы не очень полезны в этом отношении. Вот провайдер
@Override
protected FakeApplication provideFakeApplication() {
return new FakeApplication(new java.io.File("."), Helpers.class.getClassLoader(), ImmutableMap.of("play.http.router", "router.Routes"), new ArrayList<String>(), null);
}
UPDATE:
Вот обновление, основанное на приведенном ниже предложении
Внутри моего класса BaseTest
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().in(Mode.TEST).build();
}
И затем в классе тестирования обслуживания
@Before
public void beforeTest() {
Injector injector = new GuiceInjectorBuilder().bindings(bind(TagService.class).toInstance(new TagService())).injector();
tagService = injector.instanceOf(TagService.class);
}
Однако, я все еще получаю исключения с нулевым указателем, потому что TagRepository не вводится.
Ответ:
Я думал об этом немного неправильно. Если вы устанавливаете инжектор с объектом, который вам нужно вставить, тогда создайте экземпляр из этого, вы больше не получите NullPointerExceptions
@Before
public void beforeTest() {
Injector injector = new GuiceInjectorBuilder().bindings(bind(TagRepository.class).toInstance(new TagRepository())).injector();
tagService = injector.instanceOf(TagService.class);
}
Ответы
Ответ 1
Если вы расширяете WithApplication
, вы можете переопределить protected Application provideApplication()
, чтобы вернуть Application
с помощью GuiceApplicationBuilder
.
Например (на основе этого кода) вы можете создать свое приложение, добавить или переопределить привязки и т.д. и установить режим. Если вы создадите абстрактный класс, он автоматически будет работать со всеми дочерними классами.
public abstract class AbstractFakeApplicationTest extends WithApplication
{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFakeApplicationTest.class);
@Override
protected Application provideApplication()
{
return new GuiceApplicationBuilder().in(Mode.TEST)
.build();
}
@Override
public void startPlay()
{
super.startPlay();
// mock or otherwise provide a context
Http.Context.current.set(new Http.Context(1L,
Mockito.mock(RequestHeader.class),
Mockito.mock(Http.Request.class),
Collections.<String, String>emptyMap(),
Collections.<String, String>emptyMap(),
Collections.<String, Object>emptyMap()));
}
public Http.Context context()
{
return Http.Context.current.get();
}
}
Детские классы затем просто расширяют этот класс и проверяют как обычно - все DI должно происходить так же, как при обычном запуске приложения.
Здесь вы можете увидеть различные примеры
Это дает основной план того, что вам нужно сделать. Надеемся, что документы в https://playframework.com/documentation/2.4.x/JavaTestingWithGuice станут более понятными.