视频教程和配套博客:goconvey - 课时 1:优雅的单元测试

Go 语言虽然自带单元测试功能,在 GoConvey 诞生之前也出现了许多第三方辅助库。但没有一个辅助库能够像 GoConvey 这样优雅地书写代码的单元测试,简洁的语法和舒适的界面能够让一个不爱书写单元测试的开发人员从此爱上单元测试。

下载安装 GoConvey:

go get github.com/smartystreets/goconvey
  1. 在$GOPATH/src目录下新增了github.com子目录,该子目录里包含了GoConvey框架的库代码

  2. 在$GOPATH/bin目录下新增了GoConvey框架的可执行程序goconvey

API 文档

请移步 Go Walker

基本使用方法

示例代码

示例:

下面是一个能够实现整数基本四则运算(加、减、乘、除)的代码:

package main

import "errors"

func Add(a, b int) int {
return a + b
} func Subtract(a, b int) int {
return a - b
} func Multiply(a, b int) int {
return a * b
} func Division(a, b int) (int, error) {
if b == {
return , errors.New("被除数不能为 0")
}
return a / b, nil
}
func main() { }

在上面的代码中,我们实现了 4 个函数,因此需要为这 4 个函数分别书写单元测试:

package main

import (
. "github.com/smartystreets/goconvey/convey"
"testing"
) func TestAdd(t *testing.T) {
Convey("将两数相加", t, func() {
So(Add(, ), ShouldEqual, )
})
} func TestSubtract(t *testing.T) {
Convey("将两数相减", t, func() {
So(Subtract(, ), ShouldEqual, -)
})
} func TestMultiply(t *testing.T) {
Convey("将两数相乘", t, func() {
So(Multiply(, ), ShouldEqual, )
})
} func TestDivision(t *testing.T) {
Convey("将两数相除", t, func() { Convey("除以非 0 数", func() {
num, err := Division(, )
So(err, ShouldBeNil)
So(num, ShouldEqual, )
}) Convey("除以 0", func() {
_, err := Division(, )
So(err, ShouldNotBeNil)
})
})
}

首先,您需要使用官方推荐的方式导入 GoConvey 的辅助包以减少冗余的代码:. "github.com/smartystreets/goconvey/convey"

每个单元测试的名称需要以 Test 开头,例如:TestAdd,并需要接受一个类型为 *testing.T 的参数。

使用 GoConvey 书写单元测试,每个测试用例需要使用 Convey 函数包裹起来。它接受的第一个参数为 string 类型的描述;第二个参数一般为 *testing.T,即本例中的变量 t;第三个参数为不接收任何参数也不返回任何值的函数(习惯以闭包的形式书写)。

Convey 语句同样可以无限嵌套,以体现各个测试用例之间的关系,例如 TestDivision 函数就采用了嵌套的方式体现它们之间的关系。需要注意的是,只有最外层的 Convey 需要传入变量 t,内层的嵌套均不需要传入。

最后,需要使用 So 语句来对条件进行判断。在本例中,我们只使用了 3 个不同类型的条件判断:ShouldBeNilShouldEqual 和 ShouldNotBeNil,分别表示值应该为 nil、值应该相等和值不应该为 nil。有关详细的条件列表,可以参见 官方文档

测试:

go test -v

输出结果(ubuntu):

=== RUN   TestAdd

  将两数相加 ✔

 total assertion

--- PASS: TestAdd (.00s)
=== RUN TestSubtract 将两数相减 ✔ total assertions --- PASS: TestSubtract (.00s)
=== RUN TestMultiply 将两数相乘 ✔ total assertions --- PASS: TestMultiply (.00s)
=== RUN TestDivision 将两数相除
除以非 数 ✔✔
除以 ✔ total assertions --- PASS: TestDivision (.00s)
PASS
ok tttt .004s

我们可以看到,输出结果调理非常清晰,单元测试的代码写起来也非常优雅。那么,这就是全部吗?当然不是。GoConvey 不仅支持在命令行进行人工调用调试命令,还有非常舒适的 Web 界面提供给开发者来进行自动化的编译测试工作。

Web 界面

想要使用 GoConvey 的 Web 界面特性,需要在相应目录下执行 goconvey(需使用 go get 安装到 $GOPATH/bin 目录下),然后打开浏览器,访问 http://localhost:8080 ,就可以看到下以下界面:

//一般都是在项目根目录下(具体根据自己的情况)
goconvey // 确保 $GOPATH/bin 目录下存在 goconvey文件

在 Web 界面中,您可以设置界面主题,查看完整的测试结果,使用浏览器提醒等实用功能。

其它功能:

Skip

针对想忽略但又不想删掉或注释掉某些断言操作,GoConvey提供了Convey/So的Skip方法:

  • SkipConvey函数表明相应的闭包函数将不被执行
  • SkipSo函数表明相应的断言将不被执行

当存在SkipConvey或SkipSo时,测试日志中会显式打上"skipped"形式的标记:

  • 当测试代码中存在SkipConvey时,相应闭包函数中不管是否为SkipSo,都将被忽略,测试日志中对应的符号仅为一个"⚠"
  • 当测试代码Convey语句中存在SkipSo时,测试日志中每个So对应一个"✔"或"✘",每个SkipSo对应一个"⚠",按实际顺序排列
  • 不管存在SkipConvey还是SkipSo时,测试日志中都有字符串"{n} total assertions (one or more sections skipped)",其中{n}表示测试中实际已运行的断言语句数

定制断言函数

我们先看一下So的函数原型:

func So(actual interface{}, assert assertion, expected ...interface{})

第二个参数为assertion,它的原型为:

type assertion func(actual interface{}, expected ...interface{}) string

当assertion的返回值为""时表示断言成功,否则表示失败,GoConvey框架中的相关代码为:

const (
success = ""
needExactValues = "This assertion requires exactly %d comparison values (you provided %d)."
needNonEmptyCollection = "This assertion requires at least 1 comparison value (you provided 0)."
)

我们简单实现一个assertion函数:

func ShouldGt(actual interface{}, expected ...interface{}) string {
if len(expected) == {
return "缺少参数 expected..."
}
val1 := actual.(int)
val2 := expected[].(int)
if val1 <= val2{
return fmt.Sprintf("%d 不大于 %d", actual, expected[])
}
return ""
}

写一个简单的测试:

func TestGt(t *testing.T) {
time.Sleep(time.Second*) //仅仅是测试耗时
Convey("两数相乘是否大于100", t, func() {
So(, ShouldGt, )
So(, ShouldGt, )
})
}

根据ShouldGt的实现,Convey语句中第一个So将断言成功,第二个So将断言失败。
我们运行测试,查看执行结果,符合期望:

=== RUN   TestGt

  两数相乘是否大于100 ✘

Failures:

  * /home/zhou/go/src/tttt/zhou_test.go
Line :
不大于 total assertion --- FAIL: TestGt (.00s)
FAIL
exit status
FAIL tttt .002s

要点归纳总结:

  • import goconvey包时,前面加点号".",以减少冗余的代码
  • 测试函数的名字必须以Test开头,而且参数类型必须为*testing.T
  • 每个测试用例必须使用Convey函数包裹起来,推荐使用Convey语句的嵌套,即一个函数有一个测试函数,测试函数中嵌套两级Convey语句,第一级Convey语句对应测试函数,第二级Convey语句对应测试用例
  • Convey语句的第三个参数习惯以闭包的形式实现,在闭包中通过So语句完成断言
  • 使用GoConvey框架的 Web 界面特性,作为命令行的补充
  • 在适当的场景下使用SkipConvey函数或SkipSo函数
  • 当测试中有需要时,可以定制断言函数

转载:传送门

转载更好的博客:传送门

golang测试框架--smartystreets/goconvey的更多相关文章

  1. [Golang] GoConvey测试框架使用指南

    GoConvey 是一款针对Golang的测试框架,可以管理和运行测试用例,同时提供了丰富的断言函数,并支持很多 Web 界面特性. GoConvey 网站 : http://smartystreet ...

  2. golang测试

    简述 Go语言中自带有一个轻量级的测试框架testing和自带的go test命令来实现单元测试和性能测试. go test [-c] [-i] [build flags] [packages] [f ...

  3. Golang单元测试框架整理

    目录 一.单元测试是什么 二.单元测试的意义 三.Golang单元测试框架 3.1 Golang内置testing包 3.1.1 简单的测试 3.1.2 Benchmark 基准测试 3.1.3 运行 ...

  4. Golang测试技术

    本篇文章内容来源于Golang核心开发组成员Andrew Gerrand在Google I/O 2014的一次主题分享“Testing Techniques”,即介绍使用Golang开发 时会使用到的 ...

  5. Go语言打造以太坊智能合约测试框架(level1)

    传送门: 柏链项目学院 Go语言打造以太坊智能合约测试框架 前言 这是什么? 这是一个基于go语言编写的,自动化测试以太坊智能合约的开发框架,使用此框架,可以自动化的部署合约,自动测试合约内的功能函数 ...

  6. Golang 微框架 Gin 简介

    框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了.成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应 ...

  7. golang(gin框架),基于RESTFUL的跨语言远程通信尝试

    golang(gin框架),基于RESTFUL的跨语言远程通信尝试 背景: 在今年的项目实训过程中,遇到了这样的问题: 企业老师讲课实用的技术栈是Java springboot. 实训实际给我们讲课以 ...

  8. phpunit 测试框架安装

    PHPUnit是一个轻量级的PHP测试框架.它是在PHP5下面对JUnit3系列版本的完整移植,是xUnit测试框架家族的一员(它们都基于模式先锋Kent Beck的设计).来自百度百科 一.下载wg ...

  9. 某互联网后台自动化组合测试框架RF+Sikuli+Python脚本

    某互联网后台自动化组合测试框架RF+Sikuli+Python脚本 http://www.jianshu.com/p/b3e204c8651a 字数949 阅读323 评论1 喜欢0 一.**Robo ...

随机推荐

  1. ucosii(2.89)mbox 应用要点

    OSMboxCreate(void *msg)     当创建一个mbox时候,消息邮箱允许(任务或者中断)向其他一个或者几个任务发送消息.初始化msg指向消息邮箱中的消息. void*OSMboxP ...

  2. Mybatis generator自动生成代码包括实体,dao,xml文件

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration ...

  3. Alfred的配置和使用

    http://www.jianshu.com/p/f77ad047f7b0   Alfred:mac上的神兵利器,提升工作效率*n,快捷键:option + 空格.鉴于是看了池老师的<人生元编程 ...

  4. CPP-STL:STL备忘

    STL备忘(转) 1. string.empty() 不是用来清空字符串,而是判断string是否为空,清空使用string.clear(); 2. string.find等查找的结果要和string ...

  5. SpringMVC+Spring+Mybatis整合程序之整合

    因为每个人思路不一样,所以我在这边先分享自己的思路对于mybatis开发持久层(DAO:DataBase Access Object 持久层访问对象)有两种.第一种:传统的开发持久层方式即需要程序员开 ...

  6. c++中的结构体:声明 定义 初始化

    什么是结构体? 之前的学习中我们知道了数组是一个容器,而且是存放固定大小数据的容器,而且存放的元素的数据类型必须要一致. 比如数据库中有这样的一条记录学号 性别 年龄 成绩 地址应该怎样存放 结构体: ...

  7. ios之UIActionSheet

    UIActionSheet是在IOS弹出的选择按钮项,可以添加多项,并为每项添加点击事件. 为了快速完成这例子,我们打开Xcode 4.3.2, 先建立一个single view applicatio ...

  8. 常用JavaScript正则表达式整理

    在表单验证中,正则表达式书写起来特别繁琐,本文整理了15个常用的JavaScript正则表达式,其中包括用户名.密码强度.整数.数字.电子邮件地址(Email).手机号码.身份证号.URL地址. IP ...

  9. 洛谷P1001 A+B Problem

    这道题…………还是很简单!!! code: #include <iostream> #include <cstdio> using namespace std; int mai ...

  10. ZJOI2018游记Round1

    广告 ZJOI2018Round2游记 All Falls Down 非常感谢学弟学妹们捧场游记虽然这是一篇假游记 ZJOI Round1今天正式落下帷幕.在这过去的三天里遇到了很多朋友,见识了很多有 ...