使用 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的网络层完成的,所以只消耗一个HttpRequestHttpResponse不会完成一个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());
  }
}