Java: Junit a class with Inject annotation

Java: Junit a class with Inject annotation

@Singleton
public class RealWorkWindow implements WorkWindow {

    @Inject private Factory myFactory;

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

如你所见,我正在注入工厂 class(通过 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,这是有道理的,因为我不认为注入 运行s.

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

类似于https://mhaligowski.github.io/blog/2014/05/30/mockito-with-both-constructor-and-field-injection.html

中描述的问题

但我遇到的问题是 mock 使用了 IN 构造函数,因此在实例化测试对象时它仍然为空(因为我还没有调用 Mockito.init )

如果您使用 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 */
    }
}

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

Guice 的 Assisted Injection wiki page 提及:

AssistedInject generates an implementation of the factory class automatically. To use it, annotate the implementation class' constructor and the fields that aren't known by the injector:

以后:

AssistedInject maps the create() method's parameters to the corresponding @Assisted parameters in the implementation class' constructor. For the other constructor arguments, it asks the regular Injector to provide values.

因为它们只在那个时候可用,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);
  }

}