Go语言基地
Tutorilas创建模块

添加测试

现在你的代码已经稳定(干得漂亮),接下来添加一个测试。在开发过程中测试代码可以发现随着修改而引入的 bug。本文中,你将为 Hello 函数添加一个测试。

注意: 本文是系列教程的一部分,该系列始于 创建 Go 模块

Go 语言内建的单元测试支持使得在开发过程中进行测试变得更加容易。具体来说,通过使用命名约定、Go 的 testing 包以及 go test 命令,你可以快速编写和执行测试。

步骤

  1. 创建测试文件,在 greetings 目录中创建一个名为 greetings_test.go 的文件。

文件名以 _test.go 结尾,这会告知 go test 命令该文件包含测试函数。

  1. 将以下代码粘贴greetings_test.go 并保存文件:
package greetings

import (
    "testing"
    "regexp"
)

// TestHelloName 使用名称调用 greetings.Hello,检查返回值是否有效。
func TestHelloName(t *testing.T) {
    name := "Gladys"
    want := regexp.MustCompile(`\b`+name+`\b`)
    msg, err := Hello("Gladys")
    if !want.MatchString(msg) || err != nil {
        t.Errorf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
    }
}

// TestHelloEmpty 使用空字符串调用 greetings.Hello,检查是否返回错误。
func TestHelloEmpty(t *testing.T) {
    msg, err := Hello("")
    if msg != "" || err == nil {
        t.Errorf(`Hello("") = %q, %v, want "", error`, msg, err)
    }
}

在这段代码中,你:

  • 在与其测试代码相同的包中实现测试函数。
  • 创建两个测试函数来测试 greetings.Hello 函数。测试函数名称的形式为 TestName,其中 Name 描述了特定测试的内容。此外,测试函数接受一个指向 testing 包中的 testing.T 类型的指针作为参数。你使用这个参数的 methods 来报告和记录测试中的信息。
  • 实现了两个测试:
    • TestHelloName:使用一个 name 值调用 Hello 函数,并检查是否有有效的响应消息。如果调用返回错误或意外的响应消息(不包含你传入的名字),则使用 t 参数的 Errorf 方法在控制台打印一条消息。
    • TestHelloEmpty:使用空字符串调用 Hello 函数,以确认错误处理。如果调用返回非空字符串或没有错误,则使用 t 参数的 Errorf 方法在控制台打印一条消息。
  1. 从命令行运行测试,在 greetings 目录中使用 go test 命令

go test 命令会执行测试文件(文件名以 _test.go 结尾)中的测试函数(函数名以 Test 开头)。你可以添加 -v 标志以获取详细输出,列出所有测试及其结果。

测试应该通过:

$ go test
PASS
ok      example.com/greetings   0.364s

$ go test -v
=== RUN   TestHelloName
--- PASS: TestHelloName (0.00s)
=== RUN   TestHelloEmpty
--- PASS: TestHelloEmpty (0.00s)
PASS
ok      example.com/greetings   0.372s
  1. 破坏 Hello 函数 以查看失败的测试:

TestHelloName 测试检查返回值是否包含你指定的名字。为了查看失败的测试结果,修改 Hello 函数,使其响应中不包含名字。

greetings/greetings.go 中,将 Hello 函数替换为以下代码(注意高亮部分):

// Hello 返回指定人的问候语。
func Hello(name string) (string, error) {
    // 如果没有提供名字,则返回带有消息的错误。
    if name == "" {
        return name, errors.New("empty name")
    }
    // 使用随机格式创建消息。
    // message := fmt.Sprintf(randomFormat(), name)
    message := fmt.Sprint(randomFormat())
    return message, nil
}
  1. 再次运行测试greetings 目录中:

这次运行 go test 时不加 -v 标志。输出将仅显示失败测试的结果,这在你有许多测试时非常有用。TestHelloName 测试应该失败,而 TestHelloEmpty 仍然通过。

$ go test
--- FAIL: TestHelloName (0.00s)
    greetings_test.go:15: Hello("Gladys") = "Hail, %v! Well met!", <nil>, want match for `\bGladys\b`, nil
FAIL
exit status 1
FAIL    example.com/greetings   0.182s

总结

你现在为 Go 代码编写并执行了测试,学会了如何使用 Go 内建的测试框架来确保你的函数按预期行为。这种做法有助于保持代码质量,并在开发早期捕获 bug。

在接下来的(也是最后一个)主题中,你将看到如何编译和安装代码以便在本地运行。

On this page