blob字段如何更新_Go 如何编写简洁测试 -- 表格驱动测试

9045e529bcaa9ec394f48dcba21b6cdb.png

表格驱动测试是一种编写易于扩展测试用例的测试方法。表格驱动测试在 Go 语言中很常见(并非唯一),以至于很多标准库1都有使用。表格驱动测试使用匿名结构体。

在这篇文章中我会告诉你如何编写表格驱动测试。继续使用 errline repo 这个项目,现在我们来为 Wrap() 函数添加测试。Wrap() 函数用于给一个 error 在调用位置添加文件名和行数的修饰。我们尤其需要测试其中计算文件的短名称的逻辑(以粗体表示部分)。最初的 Wrap() 函数如下:

func Wrap(err error) error {
    if err == nil {
        return nil
    }
    // If error already has file line do not add it again.
    if _, ok := err.(*withFileLine); ok {
        return err
    }
    _, file, line, ok := runtime.Caller(calldepth)
    if !ok {
        file = "???"
        line = 0
    }
    short := file
    for i := len(file) - 1; i > 0; i-- {
        if file[i] == '/' {
            short = file[i+1:]
            break
        }
    }
    file = short
    return &withFileLine{err, file, line}
}

为了测试短文件名计算的逻辑更加简便,我们将这部分逻辑提取出来作为函数 getShortFilename()。代码现在变成这样:

func Wrap(err error) error {
    if err == nil {
        return nil
    }
    // If error already has file line do not add it again.
    if _, ok := err.(*withFileLine); ok {
        return err
    }
    _, file, line, ok := runtime.Caller(calldepth)
    if !ok {
        file = "???"
        line = 0
    }
    file = getShortFilename(file)
    return &withFileLine{err, file, line}
}

func getShortFilename(file string) string {
    short := file
    for i := len(file) - 1; i > 0; i-- {
        if file[i] == '/' {
            short = file[i+1:]
            break
        }
    }
    file = short
    return file
}

通过重构代码使其便于测试是很常见的做法。

我们现在通过传递多个文件名参数来测试 getShortFilename(),验证其输出结果是否符合预期。

我们先从一个空的测试函数开始:

func TestShortFilename(t *testing.T) {
}

紧接着,我们引入一个包含字段 inexpected 的匿名结构体(struct)。in 表示传递给 getShortFilename() 的参数,expected 则代表我们预期的返回结果。tests 是包含多个这样结构体的一个数组。

func TestShortFilename(t *testing.T) {
    tests := []struct {
        in       string   // input
        expected string   // expected result
    }{
        {"???", "???"},
        {"filename.go", "filename.go"},
        {"hello/filename.go", "filename.go"},
        {"main/hello/filename.go", "filename.go"},
    }
}

有了这个,我们就能通过循环来实现我们的测试方法。

func TestShortFilename(t *testing.T) {
    tests := []struct {
        in       string
        expected string
    }{
        {"???", "???"},
        {"filename.go", "filename.go"},
        {"hello/filename.go", "filename.go"},
        {"main/hello/filename.go", "filename.go"},
    }

    for _, tt := range tests {
        actual := getShortFilename(tt.in)
        if strings.Compare(actual, tt.expected) != 0 {
            t.Fail()
        }
    }
}

可以注意到,添加测试用例极其简单,只需在 tests 中添加项目即可。

这个方案可以扩展以适应于测试接受和返回多个参数的方法。

就这样了。

代码可以从 我的 github 获取。

引用

  1. 一些 Go 语言标准库的表格驱动测试例子
  • https://github.com/golang/go/blob/master/src/strconv/ftoa_test.go
  • https://github.com/golang/go/blob/master/src/path/match_test.go
  • https://github.com/golang/go/blob/master/src/archive/tar/strconv_test.go

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值