golang可组合的Hamcrest风格断言匹配器插件库gocrest的使用

Golang可组合的Hamcrest风格断言匹配器插件库gocrest的使用

gocrest是一个类似Hamcrest的Go断言库,它的匹配器是可组合的、自描述的,并且可以以更易读的形式串联起来创建灵活的断言。

包导入

import (
  "github.com/corbym/gocrest/by"
  "github.com/corbym/gocrest/then"
  "github.com/corbym/gocrest/is"
  "github.com/corbym/gocrest/has"
)

基本示例

then.AssertThat(testing, "hi", is.EqualTo("bye").Reason("we are going"))

输出:

we are going
Expected: value equal to <bye>
     but: <hi>

组合使用AllOf

then.AssertThat(t, "abcdef", is.AllOf(is.StringContaining("abc"), is.LessThan("ghi")))

异步匹配(v1.0.8及以上版本)

读取器示例

//Reader
then.WithinFiveSeconds(t, func(eventually gocrest.TestingT) {
	then.AssertThat(eventually, by.Reading(slowReader, 1024), is.EqualTo([]byte("abcdefghijklmnopqrstuv")))
})

通道示例

//channels
then.Eventually(t, time.Second*5, time.Second, func(eventually gocrest.TestingT) {
	then.AssertThat(eventually, by.Channelling(channel), is.EqualTo(3).Reason("should not fail"))
})

多个断言

// multiple assertions
then.WithinTenSeconds(t, func(eventually gocrest.TestingT) {
	then.AssertThat(eventually, by.Channelling(channel), is.EqualTo(3).Reason("should not fail"))
	then.AssertThat(eventually, by.Channelling(channelTwo), is.EqualTo("11").Reason("This is unreachable"))
})

v1.1.0 - 泛型支持

所有匹配器现在都使用泛型而不是反射。但仍有一些使用反射,例如TypeName等。

主要变化:

  • ValueContaining被拆分为StringContaining、MapContaining、MapContainingValues、MapMatchingValues、ArrayContaining和ArrayMatching
  • 不再对未知类型panic,因为类型会在编译时失败
  • Map匹配器通常需要显式知道map键值的类型,否则编译器会报错

示例:

then.AssertThat(testing, map[string]bool{"hi": true, "bye": true}, has.AllKeys[string, bool]("hi", "bye"))
  • has.Length()对类型要求严格,因为它同时适用于字符串和数组
  • is.LessThan()is.GreaterThan()(以及is.GreaterThanOrEqualTois.LessThanOrEqualTo)不再适用于复杂类型

现有匹配器

  • is.EqualTo(x)
  • is.EqualToIgnoringWhitespace(string) - 比较两个字符串,忽略空白字符
  • is.Nil() - 值必须为nil
  • is.StringContaining(expected) – 类似containsAll
  • is.MapContaining(expected) – 类似containsAll
  • is.MapContainingValues(expected) – 类似containsAll
  • is.MapMatchingValues(expected) – 类似containsAll
  • is.ArrayContaining(expected) – 类似containsAll
  • is.ArrayMatching(expected) – 类似containsAll
  • is.Not(m *Matcher) – 逻辑非
  • is.MatchForPattern(regex string) – 字符串正则表达式
  • has.FunctionNamed(string x) - 检查接口是否有函数(方法)
  • has.FieldNamed(string x) - 检查结构体是否有名为x的字段
  • is.AllOf(… *Matcher) - 所有匹配器都匹配时返回true
  • is.AnyOf(… *Matcher) - 任一匹配器匹配时返回true
  • is.GreaterThan(expected) - 检查actual > expected
  • is.LessThan(expected)
  • is.Empty() - 匹配actual是""、nil或len(actual)==0
  • is.LessThan(x)
  • is.LessThanOrEqualTo(x)
  • is.GreaterThan(x)
  • is.GreaterThanOrEqualTo(x)
  • has.Length(x) - 匹配给定值(int或匹配器)与给定值的长度
  • has.Prefix(x) - 字符串以x开头
  • has.Suffix(x) - 字符串以x结尾
  • has.Key(x) - map有键x
  • has.AllKeys(T x, T y) (或has.AllKeys([]T{x,y})) - 在map中查找类型为T的键
  • has.EveryElement(x1…xn) - 检查actual[i]是否匹配对应的期望值(x[i])
  • has.StructWithValues(map[string]*gocrest.Matcher) - 检查actual[key]是否匹配对应的期望值(x[key])

更多关于golang可组合的Hamcrest风格断言匹配器插件库gocrest的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang可组合的Hamcrest风格断言匹配器插件库gocrest的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用gocrest构建Hamcrest风格的Golang断言

gocrest是一个Golang的断言匹配库,它采用了类似Hamcrest的可组合匹配器风格,提供了更富有表现力的断言方式。下面我将介绍gocrest的核心用法和示例代码。

安装gocrest

go get github.com/corbym/gocrest

基本用法

简单断言

package main

import (
	"testing"
	"github.com/corbym/gocrest/has"
	"github.com/corbym/gocrest/is"
	"github.com/corbym/gocrest/then"
)

func TestSimpleAssertions(t *testing.T) {
	// 相等断言
	then.AssertThat(t, 42, is.EqualTo(42))
	
	// 不相等断言
	then.AssertThat(t, "hello", is.Not(is.EqualTo("world")))

	// 包含断言
	then.AssertThat(t, []int{1, 2, 3}, has.Item(is.EqualTo(2)))
	
	// 长度断言
	then.AssertThat(t, "golang", has.Length(is.GreaterThan(4)))
}

常用匹配器

基本匹配器

func TestBasicMatchers(t *testing.T) {
	// 空值检查
	var nilSlice []int
	then.AssertThat(t, nilSlice, is.Nil())
	
	// 非空检查
	then.AssertThat(t, "not empty", is.Not(is.Nil()))
	
	// 布尔检查
	then.AssertThat(t, true, is.True())
	then.AssertThat(t, false, is.False())
	
	// 类型检查
	then.AssertThat(t, 3.14, is.AllOf(
		is.Not(is.Nil()),
		is.InstanceOf(float64(0)),
	))
}

数值匹配器

func TestNumberMatchers(t *testing.T) {
	// 大于
	then.AssertThat(t, 10, is.GreaterThan(5))
	
	// 小于等于
	then.AssertThat(t, 3.14, is.LessThanOrEqualTo(3.14))
	
	// 在范围内
	then.AssertThat(t, 7, is.AllOf(
		is.GreaterThan(5),
		is.LessThan(10),
	))
}

字符串匹配器

func TestStringMatchers(t *testing.T) {
	// 包含子串
	then.AssertThat(t, "hello world", contains.String("world"))
	
	// 匹配正则
	then.AssertThat(t, "test@example.com", matches.Pattern(`^.+@.+\..+$`))
	
	// 以...开头
	then.AssertThat(t, "golang", starts.With("go"))
}

集合匹配器

func TestCollectionMatchers(t *testing.T) {
	slice := []int{1, 2, 3, 4, 5}
	
	// 包含特定元素
	then.AssertThat(t, slice, has.Item(is.EqualTo(3)))
	
	// 所有元素满足条件
	then.AssertThat(t, slice, has.All(
		is.GreaterThan(0),
		is.LessThan(10),
	))
	
	// 长度检查
	then.AssertThat(t, slice, has.Length(is.EqualTo(5)))
	
	// 映射检查
	m := map[string]int{"a": 1, "b": 2}
	then.AssertThat(t, m, has.Key(is.EqualTo("a")))
	then.AssertThat(t, m, has.Value(is.EqualTo(2)))
}

组合匹配器

gocrest的强大之处在于可以组合多个匹配器:

func TestCombinedMatchers(t *testing.T) {
	value := "Golang is awesome"
	
	then.AssertThat(t, value, is.AllOf(
		contains.String("awesome"),
		has.Length(is.GreaterThan(10)),
		starts.With("Golang"),
		is.Not(contains.String("terrible")),
	))
}

自定义匹配器

你可以创建自己的匹配器:

func isEven() *is.Matcher {
	return &is.Matcher{
		Describe: "even number",
		Matches: func(actual interface{}) bool {
			if num, ok := actual.(int); ok {
				return num%2 == 0
			}
			return false
		},
	}
}

func TestCustomMatcher(t *testing.T) {
	then.AssertThat(t, 42, isEven())
}

错误消息

当断言失败时,gocrest会提供详细的错误信息:

func TestErrorMessage(t *testing.T) {
	// 失败时会输出:
	// Expected: value equal to <42>
	//      but: <43> was not equal to <42>
	then.AssertThat(t, 43, is.EqualTo(42))
}

与标准testing包的比较

相比标准库的if x != y { t.Error() }模式,gocrest提供了:

  1. 更可读的断言语法
  2. 更详细的错误信息
  3. 可组合的匹配器
  4. 丰富的内置匹配器集合

总结

gocrest为Golang测试提供了Hamcrest风格的断言方式,通过可组合的匹配器使测试代码更清晰、更富有表现力。它特别适合需要复杂断言的场景,能够显著提高测试代码的可读性和维护性。

对于简单的测试用例,标准库可能更直接,但对于复杂的断言逻辑,gocrest能提供更好的表达能力和错误信息。

回到顶部