1. 测试的重要性
1.1 单元测试
单元测试是针对一小部分代码进行独立地测试。
单元测试的对象通常是单个函数或方法,而要测试的是它在接受给定的输入后,能否产生符合预期的输出。
单元测试的作用主要表现在以下两个方面:
- 验证程序的最小构件——函数或方法——是否如期望的方式运行
- 从程序的最小组成部分——函数或方法——中发现系统衰退的迹象。
- 衰退是在程序不断增大和变化的过程中,因修改而引入的BUG;
- 衰退意味着程序中的某段代码在修改前还有效,修改后反而无效了。
1.2 集成测试
集成测试是检查应用程序各个组件协同工作的情况。
集成测试还检查诸如网络通信、数据库访问等方面的情况,以验证整个系统是否以预期的方式运行。
集成测试比单元测试难度更大,因为它要评估整个应用程序所依赖的各个组成部分。
1.3 功能测试
功能测试是从最终用户的角度,核实软件是否满足了开发方所承诺的各项功能需求。
功能测试侧重从外部看到的程序运行情况,而并不关心软件内部的工作机制。
对用户来说,功能测试可能是最重要的测试,例如:
- 命令行工具针对用户提供的各种输入,是否都显示了正确的输出
- 对网页进行自动化测试,所有的链接是否都能正确地跳转
- 调用后台服务所提供的API,检查响应是否符合预期
1.4 测试驱动开发(强调测试先行,以测督编)
测试驱动开发强调从测试的角度考虑新功能的实现。
先通过测试来描述程序的功能,再着手编写代码,这样做有很多好处:
- 在每个代码片段的功能预期都是已知的前提下,进行代码的设计会轻松得多;
- 测试为每个功能做出的原理性定义,对编码极具指导意义;
- 在编写代码的过程中,可以随时检查有没有发生衰退;
- 随时可以使用现成的测试,来验证已经实现的代码;
开发人员可以随时改善设计,并以通过测试作为代码有效的判定标准。
2. testing包
标准库的testing包为测试提供了支持,使用该包需遵从如下约定:
- 测试代码文件与被测试代码文件位于同一目录下
- 例如[GOPATH]/src/greeting/
- 测试代码文件名采用被测试代码文件名加上"_test"后缀的形式
- greeting.go
- greeting_test.go
- 测试函数的函数名以"Test"开头,接受一个类型为T的参数
- func Greeting(s string) string { ... }
- func TestGreeting(t *testing.T) { ... }
在包目录下执行如下命令,启动单元测试:
- go test
// 基本测试
// 为了支持测试,Go语言在标准库中提供了testing包,使用该包需遵从如下约定:
//
// 1. 测试代码文件与被测试代码文件位于同一目录下
// 2. 测试代码文件名采用被测试代码文件名加上"_test"后缀的形式
// 3. 测试函数的函数名必须以"Test"开头
//
// 执行启动测试命令:go test
package module
import "testing"
func TestTrue(t *testing.T) {if true != true {t.Fatal("The world is crumbling")}
}
// 打印输出:
PASS
ok test/basic 0.473s // actual-expected模式(实际值-预期值模式)
// 变量actual表示函数的实际输出,变量expected表示期望该函数的输出,二者不同,则报告错误
package greeting
import "testing"
func TestGreeting(t *testing.T) {actual, expected := Greeting("World"), "Hello World!"if actual != expected {t.Fatalf("Actual %q, expected %q",actual, expected)}
}
// 打印输出:
--- FAIL: TestGreeting (0.00s)greeting_test.go:15: Actual "Hi World!", expected "Hello World!"
FAIL
exit status 1
FAIL test/expected 0.403s
// Package greeting return greeting
package greeting// Greeting return greeting
func Greeting(s string) string {return "Hi " + s + "!"
}