美文网首页Golang 入门资料+笔记
learn go with tests 学习笔记(一) hell

learn go with tests 学习笔记(一) hell

作者: 半亩房顶 | 来源:发表于2020-05-22 13:52 被阅读0次

    引言

    终于开始学习golang细节了,此系列笔记旨在记录学习路上遇到的一些坑,还有一些感觉需要特别注意的知识点

    环境准备

    IDE:goland
    go version: go version go1.14.1 darwin/amd64

    遇到问题

    (一)运行 go test 报错 go: cannot find main module; see 'go help modules'

    • 问题分析:其根本原因是我使用了go mod进行依赖管理,然而使用项目根目录没有go.mod文件
    • 解决办法:添加go.mod 文件,方法有二
      (1)在目录中运行 go mod init
      (2)如果使用的是goland ide,可以通过配置完成 https://goproxy.io,direct

    知识点

    (一)如何编写单元测试:

    编写测试和函数很类似,其中有一些规则

    • 程序需要在一个名为 xxx_test.go 的文件中编写
    • 测试函数的命名必须以单词 Test 开始
    • 测试函数只接受一个参数 t *testing.T
      现在这些信息足以让我们明白,类型为 *testing.T 的变量 t 是你在测试框架中的 hook(钩子),所以当你想让测试失败时可以执行 t.Fail() 之类的操作。

    hello.go

    package main
    
    import "fmt"
    
    func Hello() string {
        return "Hello, world"
    }
    
    func main() {
        fmt.Println(Hello())
    }
    

    hello_test.go

    package main
    
    import "testing"
    
    func TestHello(t *testing.T) {
        got := Hello()
        want := "Hello, world"
    
        if got != want {
            t.Errorf("got '%q' want '%q'", got, want)
        }
    }
    

    此时,运行go test 或者 go test hello_test.go hello.go(go test -v 则打印完整信息)即可:

    // go test
    PASS
    ok      learnGoWithTest/hello   0.005s
    // go test -v
    === RUN   TestHello
    --- PASS: TestHello (0.00s)
    PASS
    ok      learnGoWithTest/hello   0.006s
    

    或者测试失败时如下:

    === RUN   TestHello
        TestHello: hello_test.go:10: got '"Hello, world"' want '"Hello, world11"'
    --- FAIL: TestHello (0.00s)
    FAIL
    exit status 1
    FAIL    learnGoWithTest/hello   0.010s
    

    (二)t.Helper()

    hello.go

    package main
    
    import "fmt"
    
    const englishHelloPrefix = "Hello, "
    
    func Hello(name string) string {
        if name == "" {
            name = "World"
        }
        return englishHelloPrefix + name
    }
    
    func main() {
        fmt.Println(Hello("world"))
    }
    

    hello_test.go

    package main
    
    import "testing"
    
    func TestHello(t *testing.T) {
    
        assertCorrectMessage := func(t *testing.T, got, want string) {
            t.Helper()
            if got != want {
                t.Errorf("got '%q' want '%q'", got, want)
            }
        }
    
        t.Run("saying hello to people", func(t *testing.T) {
            got := Hello("Chris")
            want := "Hello, Chris1"
            assertCorrectMessage(t, got, want)
        })
    
        t.Run("empty string defaults to 'world'", func(t *testing.T) {
            got := Hello("")
            want := "Hello, World1"
            assertCorrectMessage(t, got, want)
        })
    }
    

    t.Helper() 需要告诉测试套件这个方法是辅助函数(helper)。通过这样做,当测试失败时所报告的行号将在函数调用中而不是在辅助函数内部。这将帮助其他开发人员更容易地跟踪问题。如果你仍然不理解,请注释掉它,使测试失败并观察测试输出。
    输出对比:
    注释掉 t.Helper()时,错误提示的行号为19,是真正抛出错误的代码行号:

    === RUN   TestHello
    --- FAIL: TestHello (0.00s)
    === RUN   TestHello/saying_hello_to_people
        TestHello/saying_hello_to_people: hello_test.go:19: got '"Hello, Chris"' want '"Hello, Chris1"'
        --- FAIL: TestHello/saying_hello_to_people (0.00s)
    === RUN   TestHello/empty_string_defaults_to_'world'
        TestHello/empty_string_defaults_to_'world': hello_test.go:19: got '"Hello, World"' want '"Hello, World1"'
        --- FAIL: TestHello/empty_string_defaults_to_'world' (0.00s)
    FAIL
    

    未注释掉 t.Helper()时,错误提示的行号为26和32,是调用包含t.Helper()代码的函数的代码行号:

    === RUN   TestHello
    --- FAIL: TestHello (0.00s)
    === RUN   TestHello/saying_hello_to_people
        TestHello/saying_hello_to_people: hello_test.go:26: got '"Hello, Chris"' want '"Hello, Chris1"'
        --- FAIL: TestHello/saying_hello_to_people (0.00s)
    === RUN   TestHello/empty_string_defaults_to_'world'
        TestHello/empty_string_defaults_to_'world': hello_test.go:32: got '"Hello, World"' want '"Hello, World1"'
        --- FAIL: TestHello/empty_string_defaults_to_'world' (0.00s)
    FAIL
    

    (三)return & switch

    func Hello(name string, language string) string {
        if name == "" {
            name = "World"
        }
    
        return greetingPrefix(language) + name
    }
    
    func greetingPrefix(language string) (prefix string) {
        switch language {
        case french:
            prefix = frenchHelloPrefix
        case spanish:
            prefix = spanishHelloPrefix
        default:
            prefix = englishHelloPrefix
        }
        return
    }
    

    一些新的概念:

    • 在我们的函数签名中,我们使用了 命名返回值(prefix string)。
    • 这将在你的函数中创建一个名为 prefix 的变量。它将被分配「零」值。这取决于类型,例如 int 是 0,对于字符串它是 ""。你只需调用 return 而不是 return prefix 即可返回所设置的值。
    • 这将显示在 Go Doc 中,所以它使你的代码更加清晰。
    • 如果没有其他 case 语句匹配,将会执行 default 分支。
    • 函数名称以小写字母开头。在 Go 中,公共函数以大写字母开始,私有函数以小写字母开头。我们不希望我们算法的内部结构暴露给外部,所以我们将这个功能私有化。

    引用


    欢迎大家关注我的公众号


    半亩房顶

    相关文章

      网友评论

        本文标题:learn go with tests 学习笔记(一) hell

        本文链接:https://www.haomeiwen.com/subject/vqgfahtx.html