@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)
Test code
@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);
}
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.
How can I test with Injection in junit? 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
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)
@Assisted
injectionGuice's Assisted Injection wiki page mentions:
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:
And later:
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.
As they are only available at that time, Guice will only inject fields after the constructor call. 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).
So let's rewrite your code according to that. Write your RealWorkWindow
as follow:
@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);
}
}