# 【译】Go 中如何进行单元测试

## 编写一个程序测试

```func Sum(numbers []int) int {
sum := 0
// 这个 bug 是故意的
for n := range numbers {
sum += n
}
return sum
}```

```package main

import (
"fmt"

"calhoun.io/testing101"
)

func main() {
testSum([]int{2, 2, 2, 4}, 10)
testSum([]int{-1, -2, -3, -4, 5}, -5)
}

func testSum(numbers []int, expected int) {
sum := testing101.Sum(numbers)
if sum != expected {
message := fmt.Sprintf("Expected the sum of %v to be %d but instead got %d!", numbers, expected, sum)
panic(message)
}
}```

`for n := range numbers {`

`for _, n := range numbers {`

## 通过 go test 进行测试

```package testing101

func Sum(numbers []int) int {
sum := 0
// 这个 bug 是故意的
for _, n := range numbers {
sum += n
}
return sum
}```

```package testing101

import (
"fmt"
"testing"
)

func TestSum(t *testing.T) {
numbers := []int{1, 2, 3, 4, 5}
expected := 15
actual := Sum(numbers)

if actual != expected {
t.Errorf("Expected the sum of %v to be %d but instead got %d!", numbers, expected, actual)
}
}```

`go test -v`

=== RUN TestSum

— PASS: TestSum (0.00s)

PASS

ok calhoun.io/testing101 0.005s

=== RUN TestSum

— FAIL: TestSum (0.00s)

sum_test.go:14: Expected the sum of [1 2 3 4 5] to be 18 but instead got 15!

FAIL

exit status 1

FAIL calhoun.io/testing101 0.005s

## 每个函数多个测试用例

```package testing101

import (
"fmt"
"testing"
)

func TestSum(t *testing.T) {
t.Run("[1,2,3,4,5]", testSumFunc([]int{1, 2, 3, 4, 5}, 15))
t.Run("[1,2,3,4,-5]", testSumFunc([]int{1, 2, 3, 4, -5}, 5))
}

func testSumFunc(numbers []int, expected int) func(*testing.T) {
return func(t *testing.T) {
actual := Sum(numbers)
if actual != expected {
t.Error(fmt.Sprintf("Expected the sum of %v to be %d but instead got %d!", numbers, expected, actual))
}
}
}```

=== RUN TestSum

=== RUN TestSum/[1,2,3,4,5]

=== RUN TestSum/[1,2,3,4,-5]

— PASS: TestSum (0.00s)

— PASS: TestSum/[1,2,3,4,5] (0.00s)

— PASS: TestSum/[1,2,3,4,-5] (0.00s)

PASS

ok calhoun.io/testing101 0.005s

## 示例作为测试

```func ExampleSum() {
numbers := []int{5, 5, 5}
fmt.Println(Sum(numbers))
// Output:
// 15
}```

Go 使用在 `ExampleXxx()` 函数底部的 “Output 注释” 部分来确定预期的输出是什么，然后在运行测试时，它将实际输出与注释中的预期输出进行比较，如果不匹配，将触发失败的测试。这样，我们可以同时编写测试和示例代码。

## 更复杂的例子

```flag.Parse()
os.Exit(m.Run())```

```package testing101

import (
"flag"
"fmt"
"os"
"testing"
)

var db struct {
Url string
}

func TestMain(m *testing.M) {
// Pretend to open our DB connection
db.Url = os.Getenv("DATABASE_URL")
if db.Url == "" {
db.Url = "localhost:5432"
}

flag.Parse()
exitCode := m.Run()

// Pretend to close our DB connection
db.Url = ""

// Exit
os.Exit(exitCode)
}

func TestDatabase(t *testing.T) {
// Pretend to use the db
fmt.Println(db.Url)
}```