Java: Junit класс с аннотацией Inject - PullRequest
1 голос
/ 04 июня 2019
@Singleton
public class RealWorkWindow implements WorkWindow {

    @Inject private Factory myFactory;

    public RealWorkWindow (
            LongSupplier longSupplier
    ) {
        defaultWindow = myFactory.create(() -> 1000L);
        workWindow = myFactory.create(longSupplier);
    } 
    ...

Как видите, я внедряю фабричный класс (внедренный через FactoryModuleBuilder)

Тестовый код

@Test
public class RealWorkWindowTest {
    private RealWorkWindow testWindow;

    @BeforeMethod
    void setup() {
        MockitoAnnotations.initMocks(this);

        testWindow = spy(new RealWorkWindow(() -> 1L));
    }

Factory.py

public interface RealWorkWindowFactory {
    RealWorkWindowFactory create(LongSupplier longSupplier);
}

Модуль

install(new FactoryModuleBuilder()
                        .implement(WorkWindow.class, RealWorkWindow.class)
                        .build(RealWorkWindowFactory.class));

Когда я запускаю тест RealWorkWindowTest тест завершается неудачно с NPE, что фабрика не существует, что имеет смысл, так как я не думаю, что инъекция выполняется.

Как я могу проверить с инъекцией в junit? или издеваться правильно?

Аналогично описанной в * 1019 проблеме

Но у меня проблема в том, что используется mock IN конструктор, поэтому при создании экземпляра тестового объекта он по-прежнему равен нулю (потому что я еще не вызывал Mockito.init)

Ответы [ 2 ]

1 голос
/ 04 июня 2019

Использовать инжектор конструктора при использовании @Assisted инъекция

Вики-страница Guice's Assisted Injection упоминает:

AssistedInject автоматически генерирует реализацию фабричного класса.Чтобы использовать его, аннотируйте конструктор класса реализации и поля, которые не известны инжектору:

И позже:

AssistedInject отображает метод create ()параметры к соответствующим @Assisted параметрам в конструкторе класса реализации. Для других аргументов конструктора он запрашивает у обычного инжектора значения.

Поскольку они доступны только в это время, Guice будет вводить поля только после вызов конструктора.Это означает, что вы должны использовать инжектор конструктора , и никакой другой механизм (если у вас нет расширения, которое позволяет @PostConstruct или подобное).

Итак, давайте перепишем вашкод в соответствии с этим.Напишите свой RealWorkWindow следующим образом:

@Singleton
public class RealWorkWindow implements WorkWindow {

  private final WorkWindow defaultWindow;
  private final WorkWindow workWindow;

  @Inject
  public RealWorkWindow(Factory myFactory, @Assisted LongSupplier longSupplier) {
    defaultWindow = myFactory.create(() -> 1000L);
    workWindow = myFactory.create(longSupplier);
  }

}

Ваш код может стать тестируемым следующим образом:

@RunWith(MockitoJunitRunner.class)
public class RealWorkWindowTest {

  @Mock
  Factory myFactory;

  @Mock
  WorkWindow defaultWindow;

  @Mock
  WorkWindow workWindow;

  RealWorkWindow realWorkWindow;

  @BeforeEach
  void setup() {
    when(myFactory.create(any(LongSupplier.class)))
        .thenReturn(defaultWindow) // First call
        .thenReturn(workWindow);   // Second call
    realWorkWindow = new RealWorkWindow(myFactory, () -> 1000L);
  }

}
1 голос
/ 04 июня 2019

Если вы используете MockitoJUnitRunner, вы можете использовать @Mock, чтобы создать макет для Фабрики и внедрить его.

@RunWith(MockitoJUnitRunner.class)
public class MyTest {

    @Mock
    private Factory myFactory;

    @InjectMocks
    private RealWorkWindow realWorkWindow;

    @Test
    public void testSomething() {
        when(myFactory.create(/* insert param here */)).thenReturn(/* insert return value here */);

        /* perform your test */
    }
}
...