Как протестировать распространение traceId с помощью WebTestClient + Micrometer Tracer?

После перехода на Spring Boot 3 и рефакторинга от Sleuth до Micrometer я больше не могу тестировать распространение traceId с помощью WebTestClient + Tracer.

Мой тест здесь состоит в том, чтобы иметь простой @RestController, где я ожидаю, что traceId будет распространяться через Tracer:

      @RestController
class MyTraceIdController(@Autowired private val tracer: Tracer) {


    @GetMapping("/trace")
    fun info(): ResponseEntity<String> {

        val traceKey = "x-b3-traceid"

        // Using tracer the traceId is retrieved at runtime but not during test
        val responseHeaders = HttpHeaders()
        responseHeaders.set(traceKey, tracer.currentSpan()?.context()?.traceId().toString())

        return ResponseEntity
            .ok()
            .headers(responseHeaders)
            .body("OK")
    }

}

И цель — протестировать его благодаря WebTestClient:

      @AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class MyTraceIdTests(@Autowired private val webTestClient: WebTestClient) {

    @Test
    fun `Assert info endpoint works as expected with webTestClient`() {

        val traceKey = "x-b3-traceid"
        val traceValue = "463ac35c9f6413ad48485a3953bb6124"

        val spanKey = "x-b3-spanid"
        val spanValue = "a2fb4a1d1a96d312"

        webTestClient.get()
            .uri("http://localhost:9080/trace")
            .header(traceKey, traceValue)
            .header(spanKey, spanValue)
            .exchange()
            .expectStatus().isOk
            .expectHeader().valueEquals(traceKey, traceValue)
            .expectBody<String>().isEqualTo("OK")
    }

}

В Sleuth при выполнении тестов внедренный BraveTracer отлично справился с заданием по распространению traceId.

С Micrometer я больше не могу вводить один правильный трассировщик для выполнения этой работы.

Чтобы проверить случай, я создал следующий образец:

https://github.com/bvoglette/trace-id-образец

Наблюдаются два поведения:

  • Во время выполнения, выполняя bootRun + curl на конечной точке, используется BraveAutoconfiguration и вводится один правильный BraveTracer => Он работает, как и ожидалось.
  • Во время тестирования я не могу ввести один правильный компонент BraveTracer => traceId всегда равен нулю

Различные подходы, которые я пробовал безуспешно

  • Чтобы использовать SimpleTracer()
  • Чтобы реализовать свой собственный компонент Tracer, следуйте документации Micrometer.
  • Чтобы использовать BraveAutoconfiguration в моем тесте или создавать экземпляры bean-компонентов на его основе

Ни одна из этих реализаций не смогла создать ни одного bean-компонента, в котором распространяется traceId.

Я ожидаю, что больше людей найдут способ просто внедрить рабочий компонент из BraveAutoconfiguration. Что мне не хватает? Должен ли я сделать свой тест по-другому?

2 ответа

Вам нужно добавить@AutoConfigureObservabilityв своем тестовом классе. По умолчанию наблюдаемость отключена в тестах.

Я также переносил свое приложение Spring-Web и Spring-интеграцию с Spring Boot 2 Sleuth на Spring Boot 3 с помощью микрометра и также столкнулся с проблемами. Я хотел настроить трассировку вручную, но у меня не было доступа к актуатору во всех модулях).

Чтобы настроить трассировку вручную, кроме обычных зависимостей микрометра, мне нужно было добавить эти две: micrometer-tracing-test и micrometer-tracing-integration-test (примечание: в большинстве случаев вам, вероятно, понадобится просто micrometer-tracing-test):

              <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-bom</artifactId>
            <version>${micrometer.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>context-propagation</artifactId>
            <version>${micrometer.version}</version>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-test</artifactId>
            <version>${micrometer.version}</version>
            <scope>test</scope> (!)
            <exclusions>
                <exclusion>
                    <groupId>com.github.tomakehurst</groupId>
                    <artifactId>wiremock-jre8-standalone</artifactId>
                </exclusion>
            </exclusions>

        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-integration-test</artifactId>
            <version>${micrometer.version}</version>
            <scope>test</scope> (!)
            <exclusions>
                <exclusion>
                    <groupId>com.github.tomakehurst</groupId>
                    <artifactId>wiremock-jre8-standalone</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
            </exclusions>
        </dependency>     

После этого я предоставил bean-компонент SimpleTracer для проверки контекста (который представляет собой реализацию Tracer, предназначенную для тестов) и вручную настроил реестр наблюдений (TestObservationRegistry). Я настроил реестр с обработчиком наблюдения - DefaultTracingObservationHandler, который передает этот тест SimpleTracer:

        @Bean
  SimpleTracer simpleTracer() {
    return new SimpleTracer();
  }

  @Bean
  TestObservationRegistry observationRegistry(SimpleTracer tracer) {
    final TestObservationRegistry testObservationRegistry = TestObservationRegistry.create();
    testObservationRegistry.observationConfig().observationHandler(new DefaultTracingObservationHandler(tracer));
    
    return testObservationRegistry;
  }

ПРИМЕЧАНИЕ. Если в вашем тесте вы получаете исключение, как показано ниже, это значит, что вы не настроили обработчик наблюдения, т. е. ваш реестр наблюдений не содержит обработчик отслеживания наблюдения. В таком случае попробуйте добавить обработчик наблюдения вручную (см. пример выше).

      java.lang.IllegalArgumentException: Context does not have an entry for key [class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext]

    at io.micrometer.observation.Observation$Context.getRequired(Observation.java:928)
    at micrometer.tracing@1.0.2/io.micrometer.tracing.handler.TracingAwareMeterObservationHandler.onStop(TracingAwareMeterObservationHandler.java:79)
    at io.micrometer.observation.ObservationHandler$FirstMatchingCompositeObservationHandler.lambda$onStop$7(ObservationHandler.java:173) 
Другие вопросы по тегам