视频教程和配套博客: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. 利用python递归实现整数转换为字符串

    def trans(num): if num // 10 == 0: return '%s'%num else: return trans(num//10)+'%s'%(num%10) a=trans ...

  2. Python基础篇 -- if while 语句

    2.7 if语句 # 单纯if if 条件: 代码块 当条件成立,执行代码块 # 二选一 if 条件: 代码块1 else: 代码块2 #当条件为真,执行代码块1,否则执行代码块2 # 多选一 没有e ...

  3. javase(14)_java基础增强

    一.Eclipse的使用 1.在eclipse下Java程序的编写和run as,debug as,及java运行环境的配置. 2.快捷键的配置,常用快捷键: •内容提示:Alt + / •快速修复: ...

  4. Spring根据XML配置文件注入对象类型属性

    这里有dao.service和Servlet三个地方 通过配过文件xml生成对象,并注入对象类型的属性,降低耦合 dao文件代码: package com.swift; public class Da ...

  5. assign, retain, copy, weak, strong

    一.assign, retain, copy 的区别(引用计数 RC reference count) 参考:IOS基础:retain,copy,assign及autorelease 1. 假设你用m ...

  6. LeetCode 朋友圈

    班上有 N 名学生.其中有些人是朋友,有些则不是.他们的友谊具有是传递性.如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友.所谓的朋友圈,是指所有朋友的集合. ...

  7. 【Java_基础】cmd下使用java命令运行class文件提示“错误:找不到或无法加载主类“的问题分析

    1.问题如下 当在命令行使用java命令执行字节码文件时提示“错误:找不到或无法加载主类” 2. 问题分析 这是由于在运行时类的全名应该是包名+类名,例如在包net.xsoftlab.baike下的类 ...

  8. redis集群理解

    Redis在3.0中也引入了集群的概念,用于解决一些大数据量和高可用的问题,但是,为了达到高性能的目的,集群不是强一致性的,使用的是异步复制,在数据到主节点后,主节点返回成功,数据被异步地复制给从节点 ...

  9. redis:高可用分析

    https://www.cnblogs.com/xuning/p/8464625.html 基于内存的Redis应该是目前各种web开发业务中最为常用的key-value数据库了,我们经常在业务中用其 ...

  10. 简单几点让你快速了解python是什么

    1.python是什么 python是一种广泛使用的高级编程语言,属于通用型编程语言,由吉多·范罗苏姆创造,第一版发布于1991年.可以视之为一种改良(加入一些其他编程语言的优点,如面向对象)的LIS ...