micrometer: Can't re-initialise TestObservationRegistry between tests
Apologies if I am missing something obvious but I’m failing to see a way to “reuse” a TestObservationRegistry across multiple tests in a test class.
Example:
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class FooServiceTest {
@Autowired
private FooService fooService;
@Autowired
private TestObservationRegistry observationRegistry;
@TestConfiguration
static class ObservationConfiguration {
@Bean
TestObservationRegistry observationRegistry() {
return TestObservationRegistry.create();
}
}
@Test
void testAddFooWithABar() {
fooService.addWithBar();
TestObservationRegistryAssert.assertThat(observationRegistry)
.hasObservationWithNameEqualTo("foo.create")
.that()
.hasLowCardinalityKeyValue("isBar", "true");
}
@Test
void testAddFooWithoutABar() {
fooService.addWithoutBar();
TestObservationRegistryAssert.assertThat(observationRegistry)
.hasObservationWithNameEqualTo("foo.create")
.that()
.hasLowCardinalityKeyValue("isBar", "false");
}
}
In the above, both tests call methods of the FooService which create similar Observations but with a slightly different KeyValue isBar
.
When I run the test, one of the tests always fails because the hasObservationWithNameEqualTo()
assertion gets the latest Observation matching the name foo.create
, and the subsequent assertion on key value fails.
What is needed (I think) is some way of “clearing”/re-initialising the TestObservationRegistry
between tests, but I can’t see any way of doing this short of annotating each test method with @DirtiesContext
, which seems like a sledgehammer to crack a nut, and slows down test runs.
Or am I going about this the wrong way?
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 17 (9 by maintainers)
Commits related to this issue
- Adds hasAnObservation assertion that allows doing arbitrary assertions; fixes gh-3674 — committed to micrometer-metrics/micrometer by marcingrzejszczak a year ago
- Adds hasAnObservation assertion that allows doing arbitrary assertions + clear method (#3679) * Adds hasAnObservation assertion that allows doing arbitrary assertions; fixes gh-3674 * Trying to fi... — committed to micrometer-metrics/micrometer by marcingrzejszczak a year ago
Don’t be so hard on yourself 😉 That’s a typical problem when running tests against a shared state. Either you lock on the state and ensure that for each of the tests from the beginning till the end you have control of it which leads of course to lower performance, or you ignore the fact that you have other tests injecting entries to your shared state but you create test data in such a way that you can later properly query them.
Example: you create a user with a name that is e.g. timestamp or name of your test + timestamp and then when you inject it to the in memory database you test that that concrete entry is there in the database. You don’t check that the database size == 1 cause in the meantime some other test could have entered something to your db.
I think that in a typical unit test setup, the
TestObservationRegistry
, as a test class field, will be newly instantiated for each test. This is only a problem with integration tests and an actual application context where a single registry instance is expected for the running server.In this case, adding a
clear()
method could help if it’s used with@BeforeEach
to ensure that the registry is empty. If developers enable parallel test execution this becomes a problem again and they would need to worry about shared state and probably use@ResourceLock
. Since the application context is itself cached by the test context framework, the context (and theTestObservationRegistry
bean) can be reused by another test class and side effects can also happen there.In short, I’m not sure this really solves the problem as by definition the registry is stateful within a live application.