@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));
    }


工厂

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


模组

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


当我运行测试RealWorkWindowTest时,由于NPE测试失败,因此工厂不存在,这是有道理的,因为我认为注入不会运行。

如何在junit中使用Injection进行测试?或正确模拟?

https://mhaligowski.github.io/blog/2014/05/30/mockito-with-both-constructor-and-field-injection.html中描述的问题类似

但是我的问题是在IN构造函数中使用了模拟,因此在实例化测试对象时它仍然为null(因为我尚未调用Mockito.init)

最佳答案

使用@Assisted注入时使用构造函数注入

Guice的Assisted Injection wiki page提到:


  AssistedInject自动生成工厂类的实现。要使用它,请注释实现类的构造函数和注入器不知道的字段:


然后:


  AssistedInject将create()方法的参数映射到实现类的构造函数中的相应@Assisted参数。对于其他构造函数参数,它要求常规Injector提供值。


由于它们仅在那时可用,因此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);
  }

}

08-04 04:20