使用 context.log().whenComplete() 对 Armeria 的装饰器进行单元测试
Unit testing Armeria's decorator using context.log().whenComplete()
我有一个 SimpleDecoratingHttpService
的子类,其中包含如下内容:
override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
ctx.log().whenComplete().thenAccept {
if (it.responseCause() == ...) {
// do stuff
}
}
return unwrap().serve(ctx, req)
}
我想测试 whenComplete()
回调中的逻辑。但是,当编写这样的测试时:
myDecorator.serve(context, request).aggregate().join()
log()
未来永远不会完成。我需要做什么才能确保 log()
未来最终完成?
正在模拟 RequestLog
完成
一个RequestLog
是由Armeria的网络层完成的,所以只消耗一个HttpRequest
或HttpResponse
不会完成一个RequestLog
。要完成它,您需要调用 RequestLogBuilder
:
中的方法
var myDecorator = new MySimpleDecoratingHttpService(...);
var ctx = ServiceRequestContext.of(
HttpRequest.of(HttpMethod.GET, "/hello"));
var req = ctx.request();
var res = myDecorator.serve(ctx, ctx.req).aggregate().join();
// Fill the log.
ctx.logBuilder().endRequest();
assert ctx.log().isRequestComplete();
ctx.logBuilder().responseHeaders(ResponseHeaders.of(200));
ctx.logBuilder().endResponse();
assert ctx.log().isComplete();
Armeria 团队使用相同的技术进行测试 BraveService
,因此您可能还想在 BraveServiceTest.java:161 上查看它。
使用真实服务器进行测试
如果您的设置太复杂而无法使用模拟,作为替代方法,您可以启动一个真正的 Armeria 服务器,以便 Armeria 为您填充日志。您可以使用 ServerRule
(JUnit 4) 或 ServerExtension
(JUnit 5) 轻松启动服务器:
class MyJUnit5Test {
static final var serviceContexts =
new LinkedBlockingQueue<ServiceRequestContext>();
@RegisterExtension
static final var server = new ServerExtension() {
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/hello", (ctx, req) -> HttpResponse.of(200));
sb.decorator(delegate -> new MySimpleDecoratingHttpService(delegate, ...));
// Record the ServiceRequestContext of each request.
sb.decorator((delegate, ctx, req) -> {
serviceContexts.add(ctx);
return delegate.serve(ctx, req);
});
}
};
@BeforeEach
void clearServiceContexts() {
serviceContexts.clear();
}
@Test
void test() {
// Send a real request.
var client = WebClient.of(server.httpUri());
var res = client.get("/hello").aggregate().join();
// Get the ServiceRequestContext and its log.
var ctx = serviceContexts.take();
var log = sctx.log().whenComplete().join();
// .. check `log` here ..
assertEquals(200, log.responseHeaders().status().code());
}
}
我有一个 SimpleDecoratingHttpService
的子类,其中包含如下内容:
override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
ctx.log().whenComplete().thenAccept {
if (it.responseCause() == ...) {
// do stuff
}
}
return unwrap().serve(ctx, req)
}
我想测试 whenComplete()
回调中的逻辑。但是,当编写这样的测试时:
myDecorator.serve(context, request).aggregate().join()
log()
未来永远不会完成。我需要做什么才能确保 log()
未来最终完成?
正在模拟 RequestLog
完成
一个RequestLog
是由Armeria的网络层完成的,所以只消耗一个HttpRequest
或HttpResponse
不会完成一个RequestLog
。要完成它,您需要调用 RequestLogBuilder
:
var myDecorator = new MySimpleDecoratingHttpService(...);
var ctx = ServiceRequestContext.of(
HttpRequest.of(HttpMethod.GET, "/hello"));
var req = ctx.request();
var res = myDecorator.serve(ctx, ctx.req).aggregate().join();
// Fill the log.
ctx.logBuilder().endRequest();
assert ctx.log().isRequestComplete();
ctx.logBuilder().responseHeaders(ResponseHeaders.of(200));
ctx.logBuilder().endResponse();
assert ctx.log().isComplete();
Armeria 团队使用相同的技术进行测试 BraveService
,因此您可能还想在 BraveServiceTest.java:161 上查看它。
使用真实服务器进行测试
如果您的设置太复杂而无法使用模拟,作为替代方法,您可以启动一个真正的 Armeria 服务器,以便 Armeria 为您填充日志。您可以使用 ServerRule
(JUnit 4) 或 ServerExtension
(JUnit 5) 轻松启动服务器:
class MyJUnit5Test {
static final var serviceContexts =
new LinkedBlockingQueue<ServiceRequestContext>();
@RegisterExtension
static final var server = new ServerExtension() {
@Override
protected void configure(ServerBuilder sb) throws Exception {
sb.service("/hello", (ctx, req) -> HttpResponse.of(200));
sb.decorator(delegate -> new MySimpleDecoratingHttpService(delegate, ...));
// Record the ServiceRequestContext of each request.
sb.decorator((delegate, ctx, req) -> {
serviceContexts.add(ctx);
return delegate.serve(ctx, req);
});
}
};
@BeforeEach
void clearServiceContexts() {
serviceContexts.clear();
}
@Test
void test() {
// Send a real request.
var client = WebClient.of(server.httpUri());
var res = client.get("/hello").aggregate().join();
// Get the ServiceRequestContext and its log.
var ctx = serviceContexts.take();
var log = sctx.log().whenComplete().join();
// .. check `log` here ..
assertEquals(200, log.responseHeaders().status().code());
}
}