Well @Injectmocks is nice and evil in one tag. Assume we have this service
@Service
public class SampleService {
private final Logger LOG = Logger.getLogger(SampleService.class.getName());
@Autowired
private SampleDependency1 dependency1;
public Long sampleMethod() {
LOG.info("Calling sampleMethod");
Long l = dependency1.calculateValue();
LOG.info("l = " + l);
return l;
}
}
and the corresponding test
@RunWith(SpringRunner.class)
@SpringBootTest
public class InjectmocksApplicationTests {
@Mock
private SampleDependency1 dependency1;
@InjectMocks
private SampleService service = new SampleService();
@Test
public void contextLoads() {
when(dependency1.calculateValue()).thenReturn(null);
final Long l = service.sampleMethod();
Assert.isNull(l, "well l should be null");
}
}
Ok, should work and will call our service with the injected mock for dependency1. Now lets add a second dependency like this:
@Service
public class SampleService {
private final Logger LOG = Logger.getLogger(SampleService.class.getName());
@Autowired
private SampleDependency1 dependency1;
@Autowired
private SampleDependency2 dependency2;
public Long sampleMethod() {
LOG.info("Calling sampleMethod");
Long l = dependency1.calculateValue();
l= dependency2.calculateValue();
LOG.info("l = " + l);
return l;
}
This will compile, but running your test will result in
java.lang.NullPointerException
at net.kambrium.example.SampleService.sampleMethod(SampleService.java:23)
because you forgot to add dependency2 to your test class. To avoid this do
1. Use constructor wiring for your dependencies
2. Use @InjectMocks wisely and go searching on your tests for usage of the service you change and adjust the test cases
I personally prefer 1. as it always starts complaining at compile time. If your are using checkstyle you will see this warning, when using field injection:
Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies"