譯文:寫在Go測試代碼中例子(原文:Testable Examples in Go)

原文: https://blog.golang.org/examplesgit

簡介

Go自動生成的文檔中有時你會看到代碼例子,這些例子還能夠經過點擊網站上的Run按鈕運行。而這些例子是從測試代碼中提取出來的。github

goexample

這些代碼例子是具備可測性的,而帶來的優勢就是當API變化的時候,代碼可以及時的同步。標準庫中有不少庫都包含代碼例子,好比strings packagegolang

這篇文章將會教會你如何給一個庫寫例子代碼。網絡

例子代碼

例子代碼都是寫在庫的測試用例集裏面的(以_test.go結尾的文件)。跟普通的測試函數不一樣的是,例子代碼的函數不接受任何參數,命令函數命名以Example開頭(普通測試函數是以Test開頭的)框架

Go的官方例子代碼庫裏能夠找到一個 stringutil庫,這個庫實現了Reverse函數ide

package stringutil_test

import (
    "fmt"

    "github.com/golang/example/stringutil"
)

func ExampleReverse() {
    fmt.Println(stringutil.Reverse("hello"))
    // Output: olleh
}

上面這段代碼應該能夠在example_test.go裏面找到。這段例子代碼會自動在godoc中的Reverse函數的說明下找到。函數

reverse

運行該庫的測試用例,咱們能夠看到相關的Example函數也跟着一塊兒運行了。測試

$ go test -v
=== RUN TestReverse
--- PASS: TestReverse (0.00s)
=== RUN: ExampleReverse
--- PASS: ExampleReverse (0.00s)
PASS
ok      github.com/golang/example/stringutil    0.009s

輸出的內容

程序是如何肯定Example函數是否PASS呢?網站

當運行Example的測試用例的時候,測試框架捕獲了其標準輸出,而且用其跟註釋中`Output: 開頭的內容進行的對比,來肯定是否調用成功ui

簡單的修改下注釋,就可讓這個測試用例FAIL了

func ExampleReverse() {
    fmt.Println(stringutil.Reverse("hello"))
    // Output: golly
}

從新運行後的效果

$ go test
--- FAIL: ExampleReverse (0.00s)
got:
olleh
want:
golly
FAIL

若是咱們把Example裏面的註釋都刪掉呢

func ExampleReverse() {
    fmt.Println(stringutil.Reverse("hello"))
}

全部Example開頭的函數雖然會寫到文檔中,可是不會做爲測試程序執行了

$ go test -v
=== RUN TestReverse
--- PASS: TestReverse (0.00s)
PASS
ok      github.com/golang/example/stringutil    0.009s

這種狀況適用於依賴外部環境,沒法做爲單側用例執行的,好比依賴一個外部的網絡服務。

例子函數名

Godoc是經過名字來將其關聯到相應的函數的

func ExampleFoo()     // 做爲Foo函數或者類型例子
func ExampleBar_Qux() // 做爲Bar類型的Qux函數例子
func Example()        // 做爲整個庫的例子

經過這種規則,godoc將ExampleReverse函數對應到了Reverse這個函數

經過增長 下劃線+小寫字母開頭的單詞做爲後綴,一個函數能夠對應多個例子。例如

func ExampleReverse()
func ExampleReverse_second()
func ExampleReverse_third()

這3個函數對對應於Reverse這個函數。

更完整的例子

有些時候一個函數的例子已經沒法說明一個函數該如何使用。

TODO 待翻譯(困死了,先睡會)

For instance, to demonstrate the sort package we should show an implementation of sort.Interface. Since methods cannot be declared inside a function body, the example must include some context in addition to the example function.

To achieve this we can use a "whole file example." A whole file example is a file that ends in _test.go and contains exactly one example function, no test or benchmark functions, and at least one other package-level declaration. When displaying such examples godoc will show the entire file.

Here is a whole file example from the sort package:

package sort_test

import (
    "fmt"
    "sort"
)

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%s: %d", p.Name, p.Age)
}

// ByAge implements sort.Interface for []Person based on
// the Age field.
type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }

func Example() {
    people := []Person{
        {"Bob", 31},
        {"John", 42},
        {"Michael", 17},
        {"Jenny", 26},
    }

    fmt.Println(people)
    sort.Sort(ByAge(people))
    fmt.Println(people)

    // Output:
    // [Bob: 31 John: 42 Michael: 17 Jenny: 26]
    // [Michael: 17 Jenny: 26 Bob: 31 John: 42]
}

A package can contain multiple whole file examples; one example per file. Take a look at the sort package's source code to see this in practice.

結論

Godoc examples are a great way to write and maintain code as documentation. They also present editable, working, runnable examples your users can build on. Use them!

By Andrew Gerrand

相關文章

相關文章
相關標籤/搜索