Ответ 1
Для любого сложного проекта 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
, поэтому вам очень редко нужно проверить, что введенные объекты non-null в ваших тестах. На самом деле, когда я комментирую конструкторы с @Inject
, я не пытаюсь проверить, являются ли параметры null
(на самом деле, мои тесты часто вводят null
в конструктор, чтобы тесты были простыми).