添加测试

现在你的代码已经进入一个稳定的状态(顺便说一句,做得很好),接下来添加一个测试。在开发过程中测试你的代码可以暴露在你修改代码时可能引入的错误。在本主题中,你将为 Hello 函数添加一个测试。

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

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

    文件名的结尾使用 _test.go 会告诉 go test 命令该文件包含测试函数。

  2. 在 greetings_test.go 中,粘贴以下代码并保存文件。
    package greetings
    
    import (
        "testing"
        "regexp"
    )
    
    // TestHelloName calls greetings.Hello with a name, checking
    // for a valid return value.
    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 calls greetings.Hello with an empty string,
    // checking for an error.
    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 类型的指针作为参数。你使用此参数的方法来报告和记录测试结果。
    • 实现两个测试
      • TestHelloName 调用 Hello 函数,传入一个 name 值,该函数应该能够返回有效的响应消息。如果调用返回错误或意外的响应消息(不包含你传入的名称),则使用 t 参数的 Errorf 方法将消息打印到控制台。
      • TestHelloEmpty 调用 Hello 函数并传入一个空字符串。此测试旨在确认你的错误处理是否有效。如果调用返回非空字符串或没有错误,则使用 t 参数的 Errorf 方法将消息打印到控制台。
  3. 在 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
    
  4. 修改 greetings.Hello 函数使其失败,以便查看失败的测试。

    TestHelloName 测试函数会检查你指定为 Hello 函数参数的名称的返回值。要查看失败的测试结果,请修改 greetings.Hello 函数,使其不再包含该名称。

    在 greetings/greetings.go 中,用以下代码替换 Hello 函数。请注意,突出显示的代码行改变了函数的返回值,就好像 name 参数被意外删除了一样。

    // Hello returns a greeting for the named person.
    func Hello(name string) (string, error) {
        // If no name was given, return an error with a message.
        if name == "" {
            return name, errors.New("empty name")
        }
        // Create a message using a random format.
        // message := fmt.Sprintf(randomFormat(), name)
        message := fmt.Sprint(randomFormat())
        return message, nil
    }
    
  5. 在 greetings 目录的命令行中,运行 go test 来执行测试。

    这次,运行不带 -v 标志的 go test。输出将仅包含失败测试的结果,这在你有很多测试时会很有用。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
    

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