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