侦探行李在集成测试中不起作用
Sleuth baggage is not working in integration test
请提示我如何让 Sleuth Baggage 在集成测试中工作。
它在测试通过模拟 HTTP 请求时按预期工作,但在测试直接调用服务时不起作用。
我的应用程序是(Spring Boot 2.5.4,Spring Cloud 2020.0.3):
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Bean
BaggageField myBaggageField() {
return BaggageField.create("my-field-name");
}
@RestController
static class MyController {
@AutowiredMyService myService;
@GetMapping
String callService() {
return myService.updateAndGet();
}
}
@Service
static class MyService {
@Autowired BaggageField baggageField;
public String updateAndGet() {
baggageField.updateValue("value");
return baggageField.getValue();
}
}
}
application.yml:
spring.sleuth.baggage.remote-fields: my-field-name
测试:
@SpringBootTest
@AutoConfigureMockMvc
class MyApplicationTests {
@Autowired
MyService myService;
@Autowired
MockMvc mockMvc;
@Test
void testBaggageByService() {
assertThat(myService.updateAndGet()).isEqualTo("value"); // FAILS
}
@Test
void testBaggageByController() throws Exception {
mockMvc.perform(get("/")).andExpect(content().string("value")); // PASS
}
}
这是预料之中的,因为您只是在调用控制器的方法。 Sleuth instrumentation 基本上是一个 Servlet Filter,它在第一个测试中没有被调用,但在第二个测试中被使用,因为它模拟接收一个真实的请求(而且,它并不是真正的集成测试)。
您可以create a span manually and set the baggage模拟您正在跳过的行为。
请阅读有关 Brave 中刷新和更新选项的文档 - https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/project-features.html#features-baggage
设置这个然后重试
// configuration
@Bean
BaggageField countryCodeField() {
return BaggageField.create("my-field-name");
}
@Bean
ScopeDecorator mdcScopeDecorator() {
return MDCScopeDecorator.newBuilder()
.clear()
.add(SingleCorrelationField.newBuilder(countryCodeField())
.flushOnUpdate()
.build())
.build();
}
编辑:
在您的评论中您声明:
Well, Sleuth instrumentation is a Servlet Filter, but additionaly there are many other instrumentations, for example for message listener, for quartz scheduler etc. I simply guess there should be also instrumentation for integration test as well
没有这样的集成,我看不出有任何意义。你必须自己开始一个跨度,在你的测试中手动并将它放在范围内。您可以在此处找到示例 https://github.com/spring-cloud/spring-cloud-sleuth/blob/v3.0.3/tests/common/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/CircuitBreakerIntegrationTests.java#L55-L71
@Autowired
Tracer tracer;
@Autowired
CircuitBreakerFactory factory;
@Test
public void should_pass_tracing_information_when_using_circuit_breaker() {
// given
Tracer tracer = this.tracer;
ScopedSpan scopedSpan = null;
try {
scopedSpan = tracer.startScopedSpan("start");
// when
Span span = this.factory.create("name").run(tracer::currentSpan);
BDDAssertions.then(span).isNotNull();
BDDAssertions.then(scopedSpan.context().traceId()).isEqualTo(span.context().traceId());
}
finally {
scopedSpan.end();
}
}
如果出于任何原因开始一个跨度应该在许多测试中重复使用,那就是我的 JUnit 5 扩展:
public class SleuthExtension implements BeforeEachCallback, AfterEachCallback {
private static final Namespace SPAN_STORE_KEY = Namespace.create(SleuthExtension.class.getName());
private static final String SPAN_KEY = "test span";
@Override
public void beforeEach(ExtensionContext context) {
Tracer tracer = SpringExtension.getApplicationContext(context)
.getBean(Tracer.class);
ScopedSpan span = tracer.startScopedSpan("span for " + context.getDisplayName());
context.getStore(SPAN_STORE_KEY)
.put(SPAN_KEY, span);
}
@Override
public void afterEach(ExtensionContext context) {
context.getStore(SPAN_STORE_KEY)
.remove(SPAN_KEY, ScopedSpan.class)
.end();
}
}
请提示我如何让 Sleuth Baggage 在集成测试中工作。 它在测试通过模拟 HTTP 请求时按预期工作,但在测试直接调用服务时不起作用。 我的应用程序是(Spring Boot 2.5.4,Spring Cloud 2020.0.3):
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Bean
BaggageField myBaggageField() {
return BaggageField.create("my-field-name");
}
@RestController
static class MyController {
@AutowiredMyService myService;
@GetMapping
String callService() {
return myService.updateAndGet();
}
}
@Service
static class MyService {
@Autowired BaggageField baggageField;
public String updateAndGet() {
baggageField.updateValue("value");
return baggageField.getValue();
}
}
}
application.yml:
spring.sleuth.baggage.remote-fields: my-field-name
测试:
@SpringBootTest
@AutoConfigureMockMvc
class MyApplicationTests {
@Autowired
MyService myService;
@Autowired
MockMvc mockMvc;
@Test
void testBaggageByService() {
assertThat(myService.updateAndGet()).isEqualTo("value"); // FAILS
}
@Test
void testBaggageByController() throws Exception {
mockMvc.perform(get("/")).andExpect(content().string("value")); // PASS
}
}
这是预料之中的,因为您只是在调用控制器的方法。 Sleuth instrumentation 基本上是一个 Servlet Filter,它在第一个测试中没有被调用,但在第二个测试中被使用,因为它模拟接收一个真实的请求(而且,它并不是真正的集成测试)。
您可以create a span manually and set the baggage模拟您正在跳过的行为。
请阅读有关 Brave 中刷新和更新选项的文档 - https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/project-features.html#features-baggage
设置这个然后重试
// configuration
@Bean
BaggageField countryCodeField() {
return BaggageField.create("my-field-name");
}
@Bean
ScopeDecorator mdcScopeDecorator() {
return MDCScopeDecorator.newBuilder()
.clear()
.add(SingleCorrelationField.newBuilder(countryCodeField())
.flushOnUpdate()
.build())
.build();
}
编辑:
在您的评论中您声明:
Well, Sleuth instrumentation is a Servlet Filter, but additionaly there are many other instrumentations, for example for message listener, for quartz scheduler etc. I simply guess there should be also instrumentation for integration test as well
没有这样的集成,我看不出有任何意义。你必须自己开始一个跨度,在你的测试中手动并将它放在范围内。您可以在此处找到示例 https://github.com/spring-cloud/spring-cloud-sleuth/blob/v3.0.3/tests/common/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/CircuitBreakerIntegrationTests.java#L55-L71
@Autowired
Tracer tracer;
@Autowired
CircuitBreakerFactory factory;
@Test
public void should_pass_tracing_information_when_using_circuit_breaker() {
// given
Tracer tracer = this.tracer;
ScopedSpan scopedSpan = null;
try {
scopedSpan = tracer.startScopedSpan("start");
// when
Span span = this.factory.create("name").run(tracer::currentSpan);
BDDAssertions.then(span).isNotNull();
BDDAssertions.then(scopedSpan.context().traceId()).isEqualTo(span.context().traceId());
}
finally {
scopedSpan.end();
}
}
如果出于任何原因开始一个跨度应该在许多测试中重复使用,那就是我的 JUnit 5 扩展:
public class SleuthExtension implements BeforeEachCallback, AfterEachCallback {
private static final Namespace SPAN_STORE_KEY = Namespace.create(SleuthExtension.class.getName());
private static final String SPAN_KEY = "test span";
@Override
public void beforeEach(ExtensionContext context) {
Tracer tracer = SpringExtension.getApplicationContext(context)
.getBean(Tracer.class);
ScopedSpan span = tracer.startScopedSpan("span for " + context.getDisplayName());
context.getStore(SPAN_STORE_KEY)
.put(SPAN_KEY, span);
}
@Override
public void afterEach(ExtensionContext context) {
context.getStore(SPAN_STORE_KEY)
.remove(SPAN_KEY, ScopedSpan.class)
.end();
}
}