I am using the prometheus library for getting metrics of my Spring Boot application (REST API). I am using the library io.prometheus.simpleclient:0.4.0
and I am including it in my Maven pom.xml. I am using the Counter
and @Autowiring (I've tried both field and constructor injection) it to one of my own classes, like such
MyCustomMetricsClass.java
@Component
public MyCustomMetricsClass {
@Autowire
private Counter counterBean;
public void myOwnMetricsMethod() {
counterBean.inc();
// do some stuff
}
THEN, I am @Autowiring this MyCustomMetricsClass
into my Service class, MyServiceClass.java
, where it seems to run fine when I run my API locally using Spring Boot embedded tomcat on port 8080 (localhost:8080). I can hit endpoints and the metrics are being reported correctly at the actuator endpoint (localhost:8080/actuator/metrics). e.g.
MyServiceClass.java
public MyServiceClass {
@Autowire
private MyCustomMetricsclass myMetrics;
public void genericServiceMethod() {
myMetrics.MyOwnMetricsMethod(); // NULL POINTER EXCEPTION ONLY DURING TEST SCOPE (GROOVY)
}
The problem is, when I run mvn install
, which triggers the local Groovy unit tests I have written, I keep getting a NULL POINTER EXCEPTION. With the debugger, I can debug the Groovy unit tests and see in my Service class, the myMetrics
variable is NULL. But I don't understand why it works fine at runtime, also, I have annotated the MyCustomMetricsClass
as a @Component annotation, so it should be a bean being scanned by Spring Component scan.
This is a multi-module project ; with the structure below
my-project (root, contains root pom.xml)
- my-api (module, contains RestController. has its own pom.xml)
- my-service (module. contains service classes, has its own pom.xml)
- my-model (module, contains all POJO/DTO model classes, has its own pom.xml)
Am I missing some dependency on my classpath? Why does it work at runtime but not during tests? (all my dependencies should have default scope) Is the autowiring broken?
Can you share the code from your unit test?
At a guess, you're using a mocking framework, maybe Mockito?
If this assumption is true, remember, your unit test won't be running up the full Spring context, so no auto-wiring will take place. You will need to inject mocks for the autowired components.
e.g.:
@RunWith(MockitoJUnitRunner.class)
public class MyServiceClassTest {
@Mock
private MyCustomMetricsClass myCustomMetricsClass;
@InjectMocks
private MyServiceClass myServiceClass;
@Test
public void shouldDoTesting() {
myServiceClass. genericServiceMethod();
verify(myMetrics).MyOwnMetricsMethod();
}
}