This is the fifth in a series of tutorials on Go language unit testing from zero to slip. It introduces how to use gocovey to better write unit tests and make the unit test results more intuitive and visual.
In the previous "Go single test series 5 - Monkey piling test", we introduced how to use monkey to pile functions and methods in unit test.
In this article, we will introduce a personalized unit testing tool - goconvey.
The sample code of Go single test from zero to slide series has been uploaded to Github, click 👉🏻 https://github.com/go-quiz/golang-unit-test-demo View the complete source code.
Introduction to gocovey
GoConvey It is a very useful Go testing framework. It is directly integrated with go test, provides many rich assertion functions, can output readable color test results at the terminal, and also supports fully automatic Web UI.
install
go get github.com/smartystreets/goconvey
Use example
We used gocovey to write unit tests for the Split function in the initial basic example. The Split function is as follows:
// split.go 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):] i = strings.Index(s, sep) } result = append(result, s) return }
The contents of unit test documents are as follows:
// split_test.go import ( "testing" c "github.com/smartystreets/goconvey/convey" // Alias import ) func TestSplit(t *testing.T) { c.Convey("Basic use case", t, func() { var ( s = "a:b:c" sep = ":" expect = []string{"a", "b", "c"} ) got := Split(s, sep) c.So(got, c.ShouldResemble, expect) // Assert }) c.Convey("Use case without separator", t, func() { var ( s = "a:b:c" sep = "|" expect = []string{"a:b:c"} ) got := Split(s, sep) c.So(got, c.ShouldResemble, expect) // Assert }) }
The command line executes the unit test, and the color results with very good readability will be output at the terminal.
Gocovey also supports nested calls as needed in unit tests, such as:
func TestSplit(t *testing.T) { // ... // You only need to pass in t when the conversation call at the top level c.Convey("Separator at beginning or end of use case", t, func() { tt := []struct { name string s string sep string expect []string }{ {"Separator at beginning", "*1*2*3", "*", []string{"", "1", "2", "3"}}, {"Separator at end", "1+2+3+", "+", []string{"1", "2", "3", ""}}, } for _, tc := range tt { c.Convey(tc.name, func() { // Nested call conference got := Split(tc.s, tc.sep) c.So(got, c.ShouldResemble, tc.expect) }) } }) }
In this way, the final test results will also be displayed at the hierarchical level.
assert methods
Gocovey provides us with many kinds of assertion methods to use in the So() function.
General equivalence class
So(thing1, ShouldEqual, thing2) So(thing1, ShouldNotEqual, thing2) So(thing1, ShouldResemble, thing2) // Used for equality of arrays, slices, map s, and structs 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)
Digital quantity comparison class
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)
Include class
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
String class
So("asdf", ShouldStartWith, "as") So("asdf", ShouldNotStartWith, "df") So("asdf", ShouldEndWith, "df") So("asdf", ShouldNotEndWith, "df") So("asdf", ShouldContainSubstring, "wait a jiff") // optional 'expected occurences' arguments? So("asdf", ShouldNotContainSubstring, "er") So("adsf", ShouldBeBlank) So("asdf", ShouldNotBeBlank)
panic class
So(func(), ShouldPanic) So(func(), ShouldNotPanic) So(func(), ShouldPanicWith, "") // or errors.New("something") So(func(), ShouldNotPanicWith, "") // or errors.New("something")
Type check class
So(1, ShouldHaveSameTypeAs, 0) So(1, ShouldNotHaveSameTypeAs, "asdf")
Time and interval classes
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())
Custom assertion method
If none of the assertion methods listed above can meet your needs, you can also customize an assertion method according to the following format.
Note: the content in < > is what you need to replace according to your actual needs.
func should<do-something>(actual interface{}, expected ...interface{}) string { if <some-important-condition-is-met(actual, expected)> { return "" // Returns an empty string indicating that the assertion passed } return "<Some descriptive messages specify why the assertion failed...>" }
WebUI
Gocovey provides a fully automatic Web UI. You only need to execute the following commands in the project directory.
goconvey
By default, a WebUI interface will be provided on the 8080 port of the machine to clearly show the unit test data of the current project.
summary
Through a complete unit test example, this paper introduces how to use gocovey tool to write test cases, manage test cases and assert test results. At the same time, it also introduces the rich and diverse output forms of test results of gocovey.
In the next article, which will be the last in this series, we will focus on how to write testable code.