Go中(testing)单元测试

195 阅读3分钟

前言

作为一名合格的开发者,不应该在程序开发完之后才开始写测试代码

1. 单元测试

使用Go标准库中的testing包来完成我们的单元测试

注意测试函数的写法:

func TestDownload(t *testing.T) 
  • 函数以大写Test开头
  • 函数参数中包含且只有一个参数t *testing.T
package testinglearn

import (
	"net/http"
	"testing"
)

const checkMark = "\u2713"  //对号(√)
const ballotX = "\u2717"   //叉号(×)

// TestDownload 确认 http 包的 Get 函数可以下载内容
func TestDownload(t *testing.T) {
	url := "http://www.baidu.com"
	statusCode := 200

	t.Log("Given the need to test downloading content.")
	{
		t.Logf("\tWhen checking %s for status code %d", url, statusCode)
		{
			resp, err := http.Get(url)
			if err != nil {
				t.Fatal("\t\tShould be able to make the Get call.", ballotX, err)
			}
			t.Log("\t\tShould be able to make the Get call.", checkMark)

			defer resp.Body.Close()

			if resp.StatusCode == statusCode {
				t.Logf("\t\tShould receive a %d status. %v", statusCode, checkMark)
			} else {
				t.Errorf("\t\tShould receive a %d status. %v %v", statusCode, ballotX, resp.StatusCode)
			}
		}
	}
}


通过调用 go test -v 来运行这个测试(-v 表示提供冗余输出),

Running tool: D:\go\bin\go.exe test -timeout 30s -run ^TestDownload$ gogo/test/testinglearn

=== RUN   TestDownload
    d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:16: Given the need to test downloading content.
    d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:18:      When checking http://www.baidu.com for status code 200
    d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:24:              Should be able to make the Get call. ✓
    d:\learnspace\gogo\test\testinglearn\testinglearn1_test.go:29:              Should receive a 200 status. ✓
--- PASS: TestDownload (0.09s)
PASS
ok      gogo/test/testinglearn  (cached)

Go 语言的测试工具只会认为以_test.go 结尾的文件是测试文件。如果没有遵从这个约定,在包里 运行 go test 的时候就可能会报告没有测试文件。一旦测试工具找到了测试文件,就会查找里 面的测试函数并执行

t.log

使用方法 t.Log来输出测试的消息,可写本次单元测试具体的内容

t.logf

可以格式化消息,与printf类似

t.Logf("\tWhen checking %s for status code %d", url, statusCode)
t.Fatal

t.Fatal 方法,让测试框架知道这个测试失败了。t.Fatal方法不但报告这个单元测试已经失败,而且会向测试输出写一些消息,而后立刻停止这个测试函数的执行。

t.Error

如果需要报告测试失败,但是并不想停止当前测试函数的执行,可以使用 t.Error 系列方法

2. 表组测试

如果测试可以接受一组不同的输入并产生不同的输出的代码,那么应该使用表组测试的方法 进行测试。表组测试除了会有一组不同的输入值和期望结果之外,其余部分都很像基础单元测试。

其实跟单元测试没有太大区别,我们只需将单元测试的代码稍作修改即可

package testinglearn

import (
	"net/http"
	"testing"
)

// TestDownload 确认 http 包的 Get 函数可以下载内容
// 并正确处理不同的状态
func TestDownload2(t *testing.T) {
	var urls = []struct {
		url        string
		statusCode int
	}{
		{
			"http://www.baidu.com",
			http.StatusOK,
		},
		{
			"http://www.test03d1.com",
			http.StatusNotFound,
		},
	}

	t.Log("Given the need to test downloading different content.")
	{
		for _, u := range urls {
			t.Logf("\tWhen checking \"%s\" for status code \"%d\"",
				u.url, u.statusCode)
			{
				resp, err := http.Get(u.url)
				if err != nil {
					t.Fatal("\t\tShould be able to Get the url.",
						ballotX, err)
				}
				t.Log("\t\tShould be able to Get the url",
					checkMark)

				defer resp.Body.Close()

				if resp.StatusCode == u.statusCode {
					t.Logf("\t\tShould have a \"%d\" status. %v",
						u.statusCode, checkMark)
				} else {
					t.Errorf("\t\tShould have a \"%d\" status %v %v",
						u.statusCode, ballotX, resp.StatusCode)
				}
			}
		}
	}
}

=== RUN   TestDownload2
    d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:25: Given the need to test downloading different content.
    d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:28:      When checking "http://www.baidu.com" for status code "200"
    d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:36:              Should be able to Get the url ✓
    d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:42:              Should have a "200" status. ✓
    d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:28:      When checking "http://www.test03d1.com" for status code "404"
    d:\learnspace\gogo\test\testinglearn\testinglearn2_test.go:33:              Should be able to Get the url. ✗ Get "http://www.test03d1.com": dial tcp: lookup www.test03d1.com: no such host
--- FAIL: TestDownload2 (0.08s)
FAIL
FAIL    gogo/test/testinglearn  0.679s


> Test run finished at 4/4/2023, 4:57:51 PM <

我们定义了一个新的结构体数组 urls,里面存储我们需要进行测试的一组数据

var urls = []struct {
		url        string
		statusCode int
	}{
		{
			"http://www.baidu.com",
			http.StatusOK,
		},
		{
			"http://www.test03d1.com",
			http.StatusNotFound,
		},
	}


再通过循环进行测试

for _, u := range urls {

...

}

参考书籍《Go语言实战》