在自动化测试中使用 JFR 事件流 API - Sip of Java
Billy Korando 于 2022 年 10 月 31 日
JDK Flight Recorder (JFR) 是一种性能分析和诊断工具,长期以来一直是 JDK 的一部分。在大部分历史中,JFR 只能用于部署的应用程序,以提供对其性能的洞察。随着 JDK 14(JEP 349)的发布,添加了 JFR 事件流 API,它提供了一种实时查看 Java 应用程序内部发生情况的方法。本文将探讨如何在自动化测试中利用 JFR 事件流 API。
在自动化测试中使用事件流 API
以下是使用 JFR 事件流在自动化测试中的完整代码示例。我们将在下面逐步介绍此代码示例的关键部分。
初始化事件流
为了配置和捕获在自动化测试期间触发的事件,我将使用 RecordingStream
。 RecordingStream
实现 AutoCloseable
,因此我们可以在 try-with-resources 块中声明它,并允许 JVM 确保在完成时关闭和清理流。
启用事件
默认情况下不会启用内置 JFR 事件,例如 jdk.FileRead
,因此需要使用 rs.enable(String)
手动启用它们。自定义事件,例如 TestEvent
,默认情况下是启用的,不需要手动启用。
还可以通过在初始化时将设置文件传递给 RecordingStream
来配置事件,并在其中启用相应的事件,如下面的示例所示
配置事件行为
可以使用 rs.onEvent(String, Runnable)
配置触发事件时应发生的操作。在下面的代码中,TestEvent
用于关闭流,稍后会详细介绍,当 jdk.FileRead
事件发生时,它将被写入 List
以供稍后检查。
启动流、运行测试和关闭流
rs.startAsync()
用于在单独的线程中启动 JFR 事件流。要测试的代码(从文件进行简单读取)使用 sampleApplication.doStuff();
执行。
代码示例中最奇怪的部分是处理流的关闭。这是必要的,因为事件大约每秒刷新到 JFR 流一次,这通常意味着某些或所有事件没有写入流,导致测试结果不准确或不一致。可以使用 Thread.sleep(long)
来强制执行此操作,但在大型测试套件中,添加大量等待可能会开始对执行测试套件所需的时间产生重大影响。
TestEvent
与 rs.onEvent("TestEvent", e -> rs.close());
和 testEvent.commit();
以及 rs.awaitTermination()
提供了一种方法,可以在所有相关事件刷新到流中后立即关闭流。 testEvent.commit();
将在测试代码执行完毕后触发 rs.onEvent("TestEvent", e -> rs.close());
,而 rs.awaitTermination()
会阻止线程执行,直到线程关闭。这最大限度地减少了测试中的任何额外等待时间。或者,可以使用 JFRUnit 等库,请务必查看“其他阅读材料”部分以获取链接。
断言行为
当然,自动化测试如何处理断言被测试代码将高度依赖于上下文。此代码示例演示了如何将事件捕获到 List
中以供稍后检查。这只是一个示例,但还有许多其他有效的方法可以使用 JFR 编写自动化测试。
其他阅读材料
使用 Flight Recorder 事件流 API 监控事件
祝您编码愉快!