golang验证JSON序列化正确性的测试插件库jsonassert的使用

Golang验证JSON序列化正确性的测试插件库jsonassert的使用

jsonassert logo

介绍

使用Go内置的测试包很难确认JSON负载(如HTTP请求或响应体)是否符合预期。jsonassert是一个易于使用的Go测试断言库,用于验证两个JSON表示在语义上是否相等。

使用方法

在测试中创建一个新的*jsonassert.Asserter,并用它来对JSON负载进行断言:

func TestWhatever(t *testing.T) {
	ja := jsonassert.New(t)
	// 查找某种负载
	name := "River Tam"
	age := 16
	ja.Assertf(payload, `
	{
		"name": "%s",
		"age": %d,
		"averageTestScore": "%s",
		"skills": [
			{ "name": "martial arts", "level": 99 },
			{ "name": "intelligence", "level": 100 },
			{ "name": "mental fortitude", "level": 4 }
		]
	}`, name, age, "99%")
}

你可以在预期的JSON结构后传入fmt.Sprintf参数。当你的测试中已经有包含预期数据的变量,或者当你的预期JSON包含可能被误解为格式指令的%字符时,这个特性可能很有用。

ja.Assertf()仅支持对字符串的断言。

仅检查存在性

JSON负载的某些属性可能难以提前知道,例如时间戳、UUID或其他随机分配的值。

对于这些类型的值,使用字符串"<<PRESENCE>>"作为预期值,jsonassert将仅验证该键是否存在(即实际的JSON具有预期的键,并且其值不为null),但不会检查其值。

例如:

func TestWhatever(t *testing.T) {
	ja := jsonassert.New(t)
	ja.Assertf(`
	{
		"time": "2019-01-28T21:19:42",
		"uuid": "94ae1a31-63b2-4a55-a478-47764b60c56b"
	}`, `
	{
		"time": "<<PRESENCE>>",
		"uuid": "<<PRESENCE>>"
	}`)
}

上面的测试会通过,但:

func TestWhatever(t *testing.T) {
	ja := jsonassert.New(t)
	ja.Assertf(`
	{
		"date": "2019-01-28T21:19:42",
		"uuid": null
	}`, `
	{
		"time": "<<PRESENCE>>",
		"uuid": "<<PRESENCE>>"
	}`)
}

上面的测试会失败,因为实际的JSON中没有time键,且uuidnull

忽略数组中的顺序

如果你的JSON负载包含一个数组,其元素的顺序不是确定性的,那么你可以在数组的第一个元素中使用"<<UNORDERED>>"指令:

func TestUnorderedArray(t *testing.T) {
	ja := jsonassert.New(t)
	payload := `["bar", "foo", "baz"]`
	ja.Assertf(payload, `["foo", "bar", "baz"]`)                  // 顺序重要,会使测试失败
	ja.Assertf(payload, `["<<UNORDERED>>", "foo", "bar", "baz"]`) // 顺序无关,会使测试通过
}

文档

你可以在GoDocs中找到这个包的文档。

贡献

欢迎贡献。请在提交PR之前阅读贡献指南并在issue中讨论功能请求。


更多关于golang验证JSON序列化正确性的测试插件库jsonassert的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang验证JSON序列化正确性的测试插件库jsonassert的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang中使用jsonassert验证JSON序列化正确性

jsonassert是一个用于测试JSON序列化正确性的Go测试库,它可以帮助你验证生成的JSON是否符合预期结构,包括字段名称、值和类型。

安装

go get github.com/kinbiko/jsonassert

基本用法

1. 简单验证

package main

import (
	"testing"
	"github.com/kinbiko/jsonassert"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func TestPersonJSON(t *testing.T) {
	ja := jsonassert.New(t)
	p := Person{Name: "Alice", Age: 30}
	expected := `{"name": "Alice", "age": 30}`

	// 将结构体序列化为JSON字符串
	actual, err := json.Marshal(p)
	if err != nil {
		t.Fatalf("Failed to marshal: %v", err)
	}

	ja.Assertf(string(actual), expected)
}

2. 验证可选字段

func TestOptionalFields(t *testing.T) {
	ja := jsonassert.New(t)
	
	// 使用"<present>"表示字段必须存在但不关心具体值
	ja.Assertf(
		`{"name": "Bob", "age": 25, "email": "bob@example.com"}`,
		`{"name": "<present>", "age": 25, "email": "<present>"}`,
	)
}

3. 正则表达式匹配

func TestRegexMatching(t *testing.T) {
	ja := jsonassert.New(t)
	
	// 使用正则表达式验证字段值格式
	ja.Assertf(
		`{"id": "user-12345", "created_at": "2023-01-01T12:00:00Z"}`,
		`{
			"id": "<<PRESENCE>>",
			"created_at": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
		}`,
	)
}

4. 数组验证

func TestArrayValidation(t *testing.T) {
	ja := jsonassert.New(t)
	
	// 验证数组内容和顺序
	ja.Assertf(
		`{"items": [1, 2, 3]}`,
		`{"items": [1, 2, 3]}`,
	)
	
	// 只验证数组长度
	ja.Assertf(
		`{"items": [1, 2, 3]}`,
		`{"items": "<<PRESENCE>>"}`,
	)
}

5. 嵌套结构验证

type Address struct {
	Street string `json:"street"`
	City   string `json:"city"`
}

type User struct {
	Name    string  `json:"name"`
	Address Address `json:"address"`
}

func TestNestedStruct(t *testing.T) {
	ja := jsonassert.New(t)
	user := User{
		Name: "Charlie",
		Address: Address{
			Street: "123 Main St",
			City:   "New York",
		},
	}

	expected := `{
		"name": "Charlie",
		"address": {
			"street": "123 Main St",
			"city": "New York"
		}
	}`

	actual, _ := json.Marshal(user)
	ja.Assertf(string(actual), expected)
}

高级特性

1. 忽略某些字段

func TestIgnoreFields(t *testing.T) {
	ja := jsonassert.New(t)
	
	// 使用"<<IGNORE>>"忽略特定字段
	ja.Assertf(
		`{"id": "123", "name": "Dave", "timestamp": "2023-01-01"}`,
		`{
			"id": "<<IGNORE>>",
			"name": "Dave",
			"timestamp": "<<IGNORE>>"
		}`,
	)
}

2. 自定义比较器

func TestCustomComparator(t *testing.T) {
	ja := jsonassert.New(t)
	
	// 为特定字段定义自定义比较逻辑
	ja.AssertfWithOptions(
		`{"score": 95.12345}`,
		`{"score": 95.12}`,
		jsonassert.Options{
			FloatPrecision: 2, // 只比较小数点后两位
		},
	)
}

最佳实践

  1. 保持测试简洁:只验证必要的字段,使用<<PRESENCE>><<IGNORE>>简化测试
  2. 优先验证结构:类型和字段名称比具体值更重要
  3. 处理动态数据:对时间戳、ID等动态生成的数据使用正则或忽略
  4. 组合使用:可以结合标准库的json.Unmarshaljsonassert进行更全面的测试

jsonassert是一个强大的工具,可以显著简化JSON序列化的测试工作,同时保持测试的准确性和可维护性。

回到顶部