译文:写在Go测试代码中例子(原文:Testable Examples in Go)

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

简介

Go自动生成的文档中有时你会看到代码例子,这些例子还可以通过点击网站上的Run按钮运行。而这些例子是从测试代码中提取出来的。

goexample

这些代码例子是具有可测性的,而带来的优点就是当API变化的时候,代码能够及时的同步。标准库中有很多库都包含代码例子,比如strings package

这篇文章将会教会你如何给一个库写例子代码。

例子代码

例子代码都是写在库的测试用例集里面的(以_test.go结尾的文件)。跟普通的测试函数不同的是,例子代码的函数不接受任何参数,命令函数命名以Example开头(普通测试函数是以Test开头的)

Go的官方例子代码库里可以找到一个 stringutil库,这个库实现了Reverse函数

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: 开头的内容进行的对比,来确定是否调用成功

简单的修改下注释,就可以让这个测试用例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

相关文章

转载于:https://my.oschina.net/goskyblue/blog/670132

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值