I have to unit test in some code(Not written by me), but I am stuck at one place. I am using Powermock and mockito. So the issue is @InjectMocks call default constructor before even testing a method, inside the default constructor, they have used a static class and a setter to set a field, and hence injecting mocks using @Inject is unable to create the instance. Is there any way to fix this with changing the API code?
RunWith(PowerMockRunner.class)
@PrepareForTest(UserGroup.class)
public class SomeServiceImplTest {
@Mock
private SomeDAOImpl SomeDAOImpl;
@Mock
private UserGroup userGroup;
@InjectMocks
SomeServiceImpl someServiceImpl;
@Test
public void testSomeMethod(){
String username = "UserToBeTest";
//Some code
//
verify(SomeDAOImpl).saveUserGroup(any(),any());
}
}
public class SomeServiceImpl {
private SomeDAOImpl someDAOImpl;
private SomeIndex someIndex;
public void setSomeDAOImpl(SomeDAOImpl someDAOImpl) {
this.someDAOImpl = someDAOImpl;
}
public SomeServiceImpl (){
someIndex; = AFinalClass.init();
setSomeDAOImpl(new SomeDAOImpl())
}
}
I want to prevent SomeServiceImpl() to getting called. Please let me know if there is any way to fix this. Can I mock constructor - But the SomeServiceImpl() gets called before testSomeMethod().
The normal solution around static method calls is to introduce a Factory.
Instead of
public class Example {
private void foo() {
Instant now = Instant.now();
}
}
use
public class Example {
private final Supplier<Instant> instantSupplier;
public Example(Supplier<Instant> instantSupplier) {
this.instantSupplier = instantSupplier;
}
public void foo() {
Instant now = instantSupplier.get();
System.out.println(now);
}
}
Now you can mock the creation of the Instant.
@RunWith(MockitoJUnitRunner.class)
public class ExampleTest {
@Mock
Supplier<Instant> instantSupplier;
@Test
public void test() {
Instant myNow = Instant.parse("2007-12-03T10:15:30.00Z");
when(instantSupplier.get()).thenReturn(myNow);
new Example(instantSupplier).foo();
}
}
Output:
2007-12-03T10:15:30Z