learn go with tests 学习笔记(一) hello world

硌手小石头 · · 723 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

引言

终于开始学习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 学习笔记(一) hello world

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

723 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传