简体   繁体   English

Java:将带有Inject注释的类添加为Junit

[英]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);
    } 
    ...

As you can see I am Injecting a factory class (injected via FactoryModuleBuilder) 如您所见,我正在注入工厂类(通过FactoryModuleBuilder注入)

Test code 测试码

@Test
public class RealWorkWindowTest {
    private RealWorkWindow testWindow;

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

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

Factory.py Factory.py

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

Module

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

When I run the test RealWorkWindowTest the test fails with NPE that factory does not exists, which makes sense since I dont think injection runs. 当我运行RealWorkWindowTest测试时,NPE测试失败,表明工厂不存在,这是有道理的,因为我认为注入不会运行。

How can I test with Injection in junit? 如何在junit中使用Injection进行测试? or mock properly? 或嘲笑吗?

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

But the problem that I have is that mock is used IN constructor so it's still a null when instantiate the test object (because i have not called Mockito.init yet) 但是我的问题是在IN构造函数中使用了模拟,因此在实例化测试对象时它仍然为null(因为我尚未调用Mockito.init)

If you use a MockitoJUnitRunner , you can use @Mock to create a mock for the Factory and inject it. 如果使用MockitoJUnitRunner ,则可以使用@Mock为Factory创建一个模拟并注入它。

@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 */
    }
}

Use constructor injection when using @Assisted injection 使用@Assisted注入时使用构造@Assisted注入

Guice's Assisted Injection wiki page mentions: Guice的Assisted Injection Wiki页面提到:

AssistedInject generates an implementation of the factory class automatically. AssistedInject自动生成工厂类的实现。 To use it, annotate the implementation class' constructor and the fields that aren't known by the injector: 要使用它,请注释实现类的构造函数和注入器不知道的字段:

And later: 然后:

AssistedInject maps the create() method's parameters to the corresponding @Assisted parameters in the implementation class' constructor. AssistedInject将create()方法的参数映射到实现类的构造函数中的相应@Assisted参数。 For the other constructor arguments, it asks the regular Injector to provide values. 对于其他构造函数参数,它要求常规的Injector提供值。

As they are only available at that time, Guice will only inject fields after the constructor call. 由于它们仅在那时可用,因此Guice将仅在构造函数调用之后注入字段。 This translates for you in the fact that you must use the constructor injection , and no other mechanism (unless you have an extension that allows @PostConstruct or similar). 这意味着您必须使用构造函数注入 ,而不要使用其他机制(除非您具有允许@PostConstruct或类似的扩展名)。

So let's rewrite your code according to that. 因此,让我们根据此代码进行重写。 Write your RealWorkWindow as follow: 编写您的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);
  }

}

Your code can then become testable as follows: 然后,您的代码可以变得可测试,如下所示:

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM