Для любого сложного проекта Guice вы должны добавить тесты, чтобы убедиться, что модули могут использоваться для создания ваших классов. В вашем примере, если B был типом, который Guice не мог понять, как создать, то Guice не смог бы создать A. Если A не требовался для запуска сервера, но был необходим, когда ваш сервер обрабатывал запрос, который может вызвать проблемы.
В своих проектах я пишу тесты для нетривиальных модулей. Для каждого модуля я использую requireBinding () , чтобы объявить, какие привязки требует модуль, но не определяет. В своих тестах я создаю инжектор Guice, используя тестируемый модуль и другой модуль, который обеспечивает необходимые привязки. Вот пример использования JUnit4 и JMock:
/** Module that provides LoginService */
public class LoginServiceModule extends AbstractModule {
@Override
protected void configure() {
requireBinding(UserDao.class);
}
@Provides
LoginService provideLoginService(UserDao dao) {
...
}
}
@RunWith(JMock.class)
public class LoginServiceModuleTest {
private final Mockery context = new Mockery();
@Test
public void testModule() {
Injector injector = Guice.createInjector(
new LoginServiceModule(), new ModuleDeps());
// next line will throw an exception if dependencies missing
injector.getProvider(LoginService.class);
}
private class ModuleDeps extends AbstractModule {
private final UserDao fakeUserDao;
public ModuleDeps() {
fakeUserDao = context.mock(UserDao.class);
}
@Override
protected void configure() {}
@Provides
Server provideUserDao() {
return fakeUserDao;
}
}
}
Обратите внимание, что тест запрашивает только поставщика. Этого достаточно, чтобы определить, что Guice может разрешить привязки. Если LoginService был создан методом провайдера, этот тест не будет проверять код в методе провайдера.
Этот тест также не проверяет, что вы связали правильную вещь с UserDao
или что UserDao
была правильно определена. Некоторые утверждают, что такие вещи редко стоит проверять; если есть проблема, это случается один раз. Вы должны «испытывать, пока страх не превратится в скуку».
Я считаю, что модульные тесты полезны, потому что я часто добавляю новые точки инъекции, и легко забыть добавить привязку.
Вызов requireBinding()
может помочь Guice отловить недостающие привязки, прежде чем он вернет ваш инжектор! В приведенном выше примере тест по-прежнему работал бы, если бы вызовов requireBinding()
не было, но мне нравится иметь их, потому что они служат документацией.
Для более сложных модулей (например, моего корневого модуля) я мог бы использовать Modules.override () , чтобы переопределить привязки, которые мне не нужны во время тестирования (например, если я хочу убедиться, что мой корневой объект, который будет создан, я, вероятно, не хочу, чтобы он создавал объект, который будет подключаться к базе данных). Для простых проектов вы можете протестировать только модуль верхнего уровня.
Обратите внимание, что Guice не будет вводить нулевые значения , если поле не помечено @Nullable
, поэтому вам очень редко нужно проверять, что введенные объекты не являются нулевыми в ваших тестах. Фактически, когда я аннотирую конструкторы с помощью @Inject
, я не пытаюсь проверить, являются ли параметры null
(на самом деле, мои тесты часто вводят null
в конструктор, чтобы тесты были простыми).