goconvey的使用

Go单测—goconvey的使用

介绍如何使用goconvey更好地编写单元测试,让单元测试结果更直观、形象。在这一篇中我们将介绍一个人性化的单元测试利器——goconvey。源码地址

一、GoConvey介绍

GoConvey是一个非常非常好用的Go测试框架,它直接与go test集成,提供了很多丰富的断言函数,能够在终端输出可读的彩色测试结果,并且还支持全自动的Web UI。

二、安装

 go get github.com/smartystreets/goconvey

三、使用示例

我们使用goconvey来为最开始的基础示例中的Split函数编写单元测试。Split函数如下:

// split.go

package goconvey_demo

import "strings"

/*
@author RandySun
@create 2022-05-01-19:19
*/

//
// Split
//  @Description: 把字符串s按照给定的分隔符sep进行分割返回字符串切片
//  @param s
//  @param sep
//  @return result
//
func Split(s, sep string) (result []string) {
	result = make([]string, 0, strings.Count(s, sep)+1)
	i := strings.Index(s, sep)
	for i > -1 {
		result = append(result, s[:i])
		s = s[i+len(sep):] // 使用len(sep)获取sep的长度
		i = strings.Index(s, sep)
	}

	result = append(result, s)
	return
}

单元测试文件内容如下:

// split_test.go


import (
	"testing"

	c "github.com/smartystreets/goconvey/convey"  // 别名导入
)

func TestSplit(t *testing.T) {
	c.Convey("基础用例", t, func() {
		var (
			s      = "a:b:c"
			sep    = ":"
			expect = []string{"a", "b", "c"}
		)
		got := Split(s, sep)
		c.So(got, c.ShouldResemble, expect) // 断言
	})

	c.Convey("不包含分隔符用例", t, func() {
		var (
			s      = "a:b:c"
			sep    = "|"
			expect = []string{"a:b:c"}
		)
		got := Split(s, sep)
		c.So(got, c.ShouldResemble, expect) // 断言
	})
}

命令行执行单元测试,会在终端输出可读性非常好的彩色结果。

goconvey_demo> go test -v
=== RUN   TestSplit

  基础用例 .


1 total assertion


  不包含分隔符用例 .


2 total assertions

--- PASS: TestSplit (0.01s)
PASS
ok      golang-unit-test-example/09goconvey_demo        0.243s

image-20220501200417110

goconvey还支持在单元测试中根据需要嵌套调用,比如:

//
//  TestChildrenSplit
//  @Description: 嵌套调用
//  @param t
//
func TestChildrenSplit(t *testing.T) {
	// 只需要在顶层的Convey调用时传入t
	c.Convey("分隔符在开头或者结尾用例", t, func() {
		tt := []struct {
			name   string
			s      string
			sep    string
			expect []string
		}{
			{"分隔符在开头", "1*2*3", "*", []string{"", "1", "2", "3"}},
			{"分隔符在结尾", "1+2+3+", "+", []string{"1", "2", "3", ""}},
		}
		for _, tc := range tt {
			c.Convey(tc.name, func() {
				// 嵌套调用Convery
				got := Split(tc.s, tc.sep)
				c.So(got, c.ShouldResemble, tc.expect)
			})
		}
	})

}

这样输出最终的测试结果时也会分层级显示。

goconvey_demo> go test -v -run Ch
=== RUN   TestChildrenSplit

  分隔符在开头或者结尾用例
    分隔符在开头 .
    分隔符在结尾 .


2 total assertions

--- PASS: TestChildrenSplit (0.00s)
PASS
ok      golang-unit-test-example/09goconvey_demo        0.303s

image-20220501201640794

四、断言方法

GoConvey为我们提供了很多种类断言方法在So()函数中使用。

一般相等类
So(thing1, ShouldEqual, thing2)
So(thing1, ShouldNotEqual, thing2)
So(thing1, ShouldResemble, thing2)		// 用于数组、切片、map和结构体相等
So(thing1, ShouldNotResemble, thing2)
So(thing1, ShouldPointTo, thing2)
So(thing1, ShouldNotPointTo, thing2)
So(thing1, ShouldBeNil)
So(thing1, ShouldNotBeNil)
So(thing1, ShouldBeTrue)
So(thing1, ShouldBeFalse)
So(thing1, ShouldBeZeroValue)
数字数量比较类
So(1, ShouldBeGreaterThan, 0)
So(1, ShouldBeGreaterThanOrEqualTo, 0)
So(1, ShouldBeLessThan, 2)
So(1, ShouldBeLessThanOrEqualTo, 2)
So(1.1, ShouldBeBetween, .8, 1.2)
So(1.1, ShouldNotBeBetween, 2, 3)
So(1.1, ShouldBeBetweenOrEqual, .9, 1.1)
So(1.1, ShouldNotBeBetweenOrEqual, 1000, 2000)
So(1.0, ShouldAlmostEqual, 0.99999999, .0001)   // tolerance is optional; default 0.0000000001
So(1.0, ShouldNotAlmostEqual, 0.9, .0001)
包含类
So([]int{2, 4, 6}, ShouldContain, 4)
So([]int{2, 4, 6}, ShouldNotContain, 5)
So(4, ShouldBeIn, ...[]int{2, 4, 6})
So(4, ShouldNotBeIn, ...[]int{1, 3, 5})
So([]int{}, ShouldBeEmpty)
So([]int{1}, ShouldNotBeEmpty)
So(map[string]string{"a": "b"}, ShouldContainKey, "a")
So(map[string]string{"a": "b"}, ShouldNotContainKey, "b")
So(map[string]string{"a": "b"}, ShouldNotBeEmpty)
So(map[string]string{}, ShouldBeEmpty)
So(map[string]string{"a": "b"}, ShouldHaveLength, 1) // supports map, slice, chan, and string
字符串类
So("asdf", ShouldStartWith, "as")
So("asdf", ShouldNotStartWith, "df")
So("asdf", ShouldEndWith, "df")
So("asdf", ShouldNotEndWith, "df")
So("asdf", ShouldContainSubstring, "稍等一下")		// optional 'expected occurences' arguments?
So("asdf", ShouldNotContainSubstring, "er")
So("adsf", ShouldBeBlank)
So("asdf", ShouldNotBeBlank)
panic类
So(func(), ShouldPanic)
So(func(), ShouldNotPanic)
So(func(), ShouldPanicWith, "")		// or errors.New("something")
So(func(), ShouldNotPanicWith, "")	// or errors.New("something")
类型检查类
So(1, ShouldHaveSameTypeAs, 0)
So(1, ShouldNotHaveSameTypeAs, "asdf")
时间和时间间隔类
So(time.Now(), ShouldHappenBefore, time.Now())
So(time.Now(), ShouldHappenOnOrBefore, time.Now())
So(time.Now(), ShouldHappenAfter, time.Now())
So(time.Now(), ShouldHappenOnOrAfter, time.Now())
So(time.Now(), ShouldHappenBetween, time.Now(), time.Now())
So(time.Now(), ShouldHappenOnOrBetween, time.Now(), time.Now())
So(time.Now(), ShouldNotHappenOnOrBetween, time.Now(), time.Now())
So(time.Now(), ShouldHappenWithin, duration, time.Now())
So(time.Now(), ShouldNotHappenWithin, duration, time.Now())
自定义断言方法

如果上面列出来的断言方法都不能满足你的需要,那么你还可以按照下面的格式自定义一个断言方法。

注意:<>中的内容是你需要按照实际需求替换的内容。

func should<do-something>(actual interface{}, expected ...interface{}) string {
    if <some-important-condition-is-met(actual, expected)> {
        return ""   // 返回空字符串表示断言通过
    }
    return "<一些描述性消息详细说明断言失败的原因...>"
}

五、WebUI

goconvey提供全自动的WebUI,只需要在项目目录下执行以下命令。

goconvey

默认就会在本机的8080端口提供WebUI界面,十分清晰地展现当前项目的单元测试数据。

image-20220501202116246

image-20220501202315903

六、总结

本文通过一个完整的单元测试示例,介绍了如何使用goconvey工具编写测试用例、管理测试用例、断言测试结果,同时也介绍了goconvey丰富多样的测试结果输出形式。

posted @ 2022-05-03 15:39  RandySun  阅读(574)  评论(0编辑  收藏  举报