介绍用于自动化样本测试的 Exemplar
这篇文章介绍了一个名为 Exemplar 的新库。Exemplar 的目标是确保用户获得他们期望看到的输出。它处理样本发现、规范化(语义上等效的结果,可能来自不同的环境)和灵活的输出验证。它调用环境中要调用的任何命令行工具。例如,您还可以调用 curl
来验证服务 API 响应。
Gradle 使用此库来验证文档中的示例,并从集成测试中删除样板代码。
Exemplar 可以使用 JUnit 测试运行器(推荐)或使用其 API 进行配置。请参阅下面的示例以及 Exemplar GitHub 仓库 中的示例。
Exemplar 的用例
文档示例的准确性非常重要。想象一下,尝试学习新事物,但示例无法正常工作时的沮丧心情。
我们认为 Exemplar 最适合用作文档检查机制。但是,它并不意味着要替代其他形式的集成测试。
Exemplar 的独特之处在于它允许发现嵌入在结构化文档中的样本,以及 OutputNormalizers
(捆绑和自定义的),在“更传统”的集成测试中使用样本项目的便利(通过 @UsesSample("path/to/sample")
),并允许在执行之前以编程方式修改样本(用于额外的环境设置,也许)(SampleModifier
)。
Exemplar 专注于日志记录和退出代码输出,验证其他副作用很麻烦(检查创建的文件可能需要额外的命令)。此外,虽然 Exemplar 可用于任何工具,但它只有针对 JVM 项目的 API。
样本项目测试入门
Exemplar 中的 sample-discovery
库将考虑样本根目录下任何包含 *.sample.conf
文件的目录作为样本项目。
样本配置文件是用 HOCON 编写的,它告诉 sample-check
如何运行样本项目。它可以很简单
executable: echo
args: "Hello World"
… 或者更复杂,包含多个步骤
commands: [{
executable: gradle
args: originalInputs incrementalReverse
expected-output-file: originalInputs.out
allow-additional-output: true
}, {
executable: gradle
args: --quiet removeOutput incrementalReverse
expected-output-file: incrementalTaskRemovedOutput.out
allow-disordered-output: true
}]
请参阅文档中的 样本配置参考,了解有哪些选项可用。
然后,JUnit 测试声明哪个 @SampleRunner
和样本测试的其他方面。
@RunWith(GradleSamplesRunner.class)
@SamplesRoot("src/docs/samples")
@SamplesOutputNormalizers({JavaObjectSerializationOutputNormalizer.class, FileSeparatorOutputNormalizer.class})
public class SamplesIntegrationTest {}
执行此测试将发现并运行外部(即,非嵌入式)样本项目,并生成您期望的 JUnit 测试报告。
嵌入式样本测试入门
Exemplar 可以使用 Asciidoctor 的 AST 在 Asciidoctor 源文件中发现样本。以下是一个使用 SampleModifiers
来设置样本环境的示例。
.Sample title
====
[.testable-sample] (1)
=====
.hello.rb (2)
[source,ruby] (3)
-----
puts "hello, #{ARGV[0]}" (4)
-----
[.sample-command] (5)
-----
$ ruby hello.rb world (6)
hello, world (7)
-----
=====
====
请阅读 嵌入式样本文档,了解使此功能正常工作所需的 Asciidoctor 元素。
我们使用指向 docs/
根目录的 EmbeddedSamplesRunner
运行此测试,Exemplar 将在该目录中查找文档文件。
@RunWith(EmbeddedSamplesRunner.class)
@SamplesRoot("docs")
@SampleModifiers({SetupEnvironmentSampleModifier.class, ExtraCommandArgumentsSampleModifier.class})
public class EmbeddedSamplesIntegrationTest {}
执行此测试将从 Asciidoctor 中提取代码到一个临时项目中,运行它,并验证它是否与文档中声明的输出匹配。
采用和贡献
开始的最佳方法是阅读 Exemplar 文档并查看 Exemplar 的样本 和 样本测试。
在撰写本文时,Exemplar 的版本为 0.6,这意味着 API 可能会在 v1.0 之前发生变化。也就是说,鉴于 API 已经过了一些修订,并且已被 Gradle 采用,在 1.0 版本之前不太可能出现重大变化。
以下是一些可能对库进行良好扩展的内容,如果您渴望提出想法或向 gradle/exemplar GitHub 仓库 提交拉取请求,我将不胜感激。
- 更多标准的规范器,例如日期、时间或持续时间的规范化
- 为搜索索引生成结构化元数据
- 允许在示例配置文件中内联预期输出
- 在 Markdown 或其他文档格式中嵌入样本发现 (#2938)
如果您想获得有关采用或贡献此项目的指导,请联系我 (@eriwen on Twitter).