使用 Go-Lookslike 测试数据形状
作者Andrew Cholakian

我很荣幸向大家介绍我们在 Elastic 开发的一种新的开源 Go 测试/架构验证库。它的名字叫做 Lookslike。Lookslike 允许您以类似于 JSON 架构的方式与 Golang 数据结构形状进行匹配,但它比 JSON 更强大,与 Go 更为相似。它有很多在任何现有 Go 测试库中都不具备的功能。

让我们通过一个示例来直接看看它的功能:

// This library lets us check that a data-structure either similar to, or exactly like a certain schema.
// For example we could test whether a pet is a dog or a cat, using the code below.

// A dog named rover
rover := map[string]interface{}{"name": "rover", "barks": "often", "fur_length": "long"}
// A cat named pounce
pounce := map[string]interface{}{"name": "pounce", "meows": "often", "fur_length": "short

运行上面的代码将显示如下结果。

Checked rover, validation status true, errors: []
Checked pounce, validation status false, errors: [@Path 'barks': expected this key to be present @Path 'meows': unexpected field encountered during strict validation]

在这里,我们可以看到狗“rover”按预期那样匹配了,但猫“pounce”未按预期匹配,产生了两个错误。一个错误是未定义“barks”键;另一个错误是意外出现一个多余的键“meows”。

由于 Lookslike 通常是用于测试上下文中的,因此,我们开发了 testslike.Test帮助器,它可以生成格式良好的测试输出。您只需将上例中的最后几行改为下面显示的内容即可。

testslike.Test(t, dogValidator, rover)
testslike.Test(t, dogValidator, pounce)

复合

Lookslike 中的一个关键概念就是能够合并验证器。假设我们需要单独的 cat 和 dog 验证器,但又不想在每个验证器中重新定义像“name”和“fur_length”这样的通用字段。让我们来看看下面的示例是如何实现的。

pets := []map[string]interface{}{
    {"name": "rover", "barks": "often", "fur_length": "long"},
    {"name": "lucky", "barks": "rarely", "fur_length": "short"},
    {"name": "pounce", "meows": "often", "fur_length": "short"},
    {"name": "peanut", "meows": "rarely", "fur_length": "long"},
}

// We can see that all pets have the "fur_length" property, but that only cats meow, and dogs bark.
// We can concisely encode this in

为什么构建 Lookslike

Lookslike 源自 Elastic 的 Heartbeat项目。Heartbeat 是运行时间解决方案后面的代理,它会 ping 端点,然后报告端点是否在正常运行。Heartbeat 的最终输出是 Elasticsearch 文档,在 Golang 代码库中以“map string interface{}”类型表示。测试这些输出文档是创建这个库的需求所在,尽管现在它在 Beats 代码库的其他地方使用。

我们面临的挑战是:

  • 有些字段的数据不需要精确匹配,例如“monitor.duration”,它用于计算执行所花的时间。它可能会在每次运行中产生不同的结果。我们需要一种方法来松散地匹配数据
  • 在任何给定的测试中,很多字段与其他测试共享,只有少数字段是不同的。我们希望能够通过编写不同的字段定义来减少代码重复。
  • 我们希望良好的测试输出能够针对各个字段失败分别显示一个错误,因此需要“testslike”测试帮助器。

鉴于这些挑战,我们做出了以下设计决策:

  • 我们希望架构灵活,并且希望开发人员能够轻松地创建新的匹配器。
  • 我们希望所有架构都是可组合和可嵌套的,这样,如果您在一个文档中嵌套了另一个文档,就可以合并架构而无需复制一堆代码了。
  • 我们需要一个好的测试帮助器让测试失败易于读取。

主要类型

Lookslike 的体系结构解析两个主要类型:“Validator”和“IsDef”。“Validator”是编译给定架构的结果。它是一个接受任意数据结构并返回结果的函数。“IsDef”是用于匹配单个字段的类型。您可能想知道为什么它们之间有区别。事实上,我们将来可能会合并这两个类型。但是,主要原因是“IsDef”在文档结构中获取了关于其位置的额外参数,允许它基于该上下文执行高级验证。“Validator”函数不接收额外的上下文,但更便于用户执行(它们只接受“interface{}”并对其进行验证)。

有关编写自定义“IsDefs”的示例,只需参阅文件即可。您可以将新的“IsDef”添加到自己的源来进行扩展。

现场示例

我们在 Beats 中大量使用了 Lookslike。通过此 github 搜索,可以找到大量用法示例。

我们需要您的帮助!

如果您对 Lookslike 感兴趣,请在 repo上提交拉取请求!我们可以特别使用一组更全面的“IsDef”。


想要更多了解Elastic技术,欢迎关注和报名参加webinar,近期安排如下:

2020年2月19日(星期三)15:00-16:00
使用Elastic Stack构建全方位可观察性实例

2020年2月26日(星期三)15:00-16:00
Kibana Lens 网络研讨会

2020年3月4日(星期三)15:00-16:00
Elastic Endpoint Security 概述网络

2020年3月11日(星期三)15:00-16:00
使用Elastic Stack监控网站资源


Elastic
44 声望986 粉丝

Elastic 是一家专注搜索的企业。作为 Elastic Stack(Elasticsearch、Kibana、Beats 和 Logstash)的开发者,Elastic 构建了自管理型和 SaaS 型产品。