测试
longestString/longestString.go
package main
//Nonrepeating : method of double points(双指针法)
func Nonrepeating(s string) int {
//空值判断
if len(s) == 0 {
return 0
}
//定义两个指针start,move
start, move, length := 0, 0, 0
//定义一个map用作存储对应字符以及其在字符串中的index
hmap := map[rune]int{}
a := []rune(s)
for ; move < len(a); move++ {
index, ok := hmap[a[move]]
if ok && index >= start {
start = index + 1
}
hmap[a[move]] = move
tmpLen := move - start
if tmpLen >= length {
length = tmpLen
}
}
return length + 1
}
longestString/longestString_test.go
package main
import "testing"
func TestNonrepeating(t *testing.T) {
tests := []struct {
example string
lenOfNonrepeat int
}{
//normal example
{"bbbbb", 1},
{"abccba", 3},
{"pwwkew", 3},
//edge example
{"", 0},
{"a", 1},
{"abcabcabcd", 4},
//chinese example
{"一二三二一", 3},
{"这里是慕课网", 6},
{"黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花", 8},
}
for _, test := range tests {
if actual := Nonrepeating(test.example); actual != test.lenOfNonrepeat {
t.Errorf("Nonrepeatinh(%s); got %d; expect %d", test.example, actual, test.lenOfNonrepeat)
}
}
}
- 传统测试
- 测试数据和测试逻辑混在一起
- 出错信息不一致
- 一旦一个数据出错测试全部结束
- 表格驱动测试
- 分离的测试数据和测试逻辑
- 明确的出错信息
- 可以部分失败
- go语言的语法使我们更易实践表格驱动测试
代码覆盖率和性能测试
go test -coverprofile=c.out //生成c.out文件,该文件用于查询测试所覆盖到的代码
go tool cover -html=c.out //查看所覆盖到的代码(一般会强制开启浏览器)
//性能测试
package main
import "testing"
func TestNonrepeating(t *testing.T) {
tests := []struct {
example string
lenOfNonrepeat int
}{
//normal example
{"bbbbb", 1},
{"abccba", 3},
{"pwwkew", 3},
//edge example
{"", 0},
{"a", 1},
{"abcabcabcd", 4},
//chinese example
{"一二三二一", 3},
{"这里是慕课网", 6},
{"黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花", 8},
}
for _, test := range tests {
if actual := Nonrepeating(test.example); actual != test.lenOfNonrepeat {
t.Errorf("Nonrepeatinh(%s); got %d; expect %d", test.example, actual, test.lenOfNonrepeat)
}
}
}
func BenchmarkNonrepeating(b *testing.B) {
//example
example := "黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花"
ans := 8
for i := 0; i < 23; i++ {
example += example
}
for i := 0; i < b.N; i++ {
if actual := Nonrepeating(example); actual != ans {
b.Errorf("Nonrepeatinh(%s); got %d; expect %d", example, actual, ans)
}
}
}
//terminal输入
go test -bench .
//termanal输出
goos: linux
goarch: amd64
pkg: longestString
BenchmarkNonrepeating-8 1 5816244552 ns/op
PASS
ok longestString 5.859s
使用pprof进行性能调优
go test -bench . -cpuprofile cpu.out
go tool pprof cpu.out
//在pprof交互式中输入web
web
udi@udi:~/Udi_work_space/Udi_ws_go/muke/9/1/longestString$ go tool pprof cpu.out
File: longestString.test
Type: cpu
Time: Sep 17, 2020 at 5:38pm (CST)
Duration: 5.31s, Total samples = 6.22s (117.08%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) web
(pprof) qiut
unrecognized command: "qiut"
(pprof) exit
优化后
longestString/longestString.go
package main
//放外面是为了测试性能时,该步骤只需执行一次
var hmap = make([]int, 0xffff)
//Nonrepeating : method of double points(双指针法)
func Nonrepeating(s string) int {
//空值判断
if len(s) == 0 {
return 0
}
//定义两个指针start,move
start, move, length := 0, 0, 0
//定义一个map用作存储对应字符以及其在字符串中的index
// hmap := map[rune]int{}
a := []rune(s)
// for ; move < len(a); move++ {
// index, ok := hmap[a[move]]
// if ok && index >= start {
// start = index + 1
// }
// hmap[a[move]] = move
// tmpLen := move - start
// if tmpLen >= length {
// length = tmpLen
// }
// }
//reset hmap
for i := 0; i < len(hmap); i++ {
hmap[i] = -1
}
for ; move < len(a); move++ {
value := hmap[a[move]]
if value != -1 && value >= start {
start = value + 1
}
hmap[a[move]] = move
tmpLen := move - start
if tmpLen >= length {
length = tmpLen
}
}
return length + 1
}
longestString/longestString_test.go
package main
import "testing"
func TestNonrepeating(t *testing.T) {
tests := []struct {
example string
lenOfNonrepeat int
}{
//normal example
{"bbbbb", 1},
{"abccba", 3},
{"pwwkew", 3},
//edge example
{"", 0},
{"a", 1},
{"abcabcabcd", 4},
//chinese example
{"一二三二一", 3},
{"这里是慕课网", 6},
{"黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花", 8},
}
for _, test := range tests {
if actual := Nonrepeating(test.example); actual != test.lenOfNonrepeat {
t.Errorf("Nonrepeatinh(%s); got %d; expect %d", test.example, actual, test.lenOfNonrepeat)
}
}
}
func BenchmarkNonrepeating(b *testing.B) {
//example
example := "黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花"
ans := 8
for i := 0; i < 23; i++ {
example += example
}
b.Logf("len(example) = %d", len(example))
b.ResetTimer()
for i := 0; i < b.N; i++ {
if actual := Nonrepeating(example); actual != ans {
b.Errorf("Nonrepeatinh(%s); got %d; expect %d", example, actual, ans)
}
}
}
测试http服务器
web_test.go
package main
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
)
type TestUserError string
func (e TestUserError) Error() string {
return e.Message()
}
func (e TestUserError) Message() string {
return string(e)
}
func errPanic(writer http.ResponseWriter, request *http.Request) error {
panic(123)
}
func errUserError(writer http.ResponseWriter, request *http.Request) error {
return TestUserError("user error")
}
func errNotFound(writer http.ResponseWriter, request *http.Request) error {
return os.ErrNotExist
}
func errPermission(writer http.ResponseWriter, request *http.Request) error {
return os.ErrPermission
}
func errUnknow(writer http.ResponseWriter, request *http.Request) error {
return errors.New("unknow error!")
}
func errNoError(writer http.ResponseWriter, request *http.Request) error {
fmt.Fprintf(writer, "no error!")
return nil
}
var tests = []struct {
h errHandle
code int
message string
}{
{errPanic, 500, "Internal Server Error"},
{errUserError, 400, "user error"},
{errNotFound, 404, "Not Found"},
{errPermission, 403, "Forbidden"},
{errUnknow, 500, "Internal Server Error"},
{errNoError, 200, "no error!"},
}
// TestCatchRootRouter : make a fake server to test
func TestCatchRootRouter(t *testing.T) {
for _, test := range tests {
response := httptest.NewRecorder()
request := httptest.NewRequest(
http.MethodGet,
"https://www.imooc.com", nil,
)
f := catchRootRouter(test.h)
f(response, request)
verifyResponse(response.Result(), test.code, test.message, t)
}
}
//TestCatchRootRouterServer : make a really server to test
func TestCatchRootRouterInServer(t *testing.T) {
for _, test := range tests {
f := catchRootRouter(test.h)
server := httptest.NewServer(http.HandlerFunc(f))
result, _ := http.Get(server.URL)
verifyResponse(result, test.code, test.message, t)
}
}
// verifyResponse :
func verifyResponse(response *http.Response, exceptedCode int, exceptedMsg string, t *testing.T) {
all, _ := ioutil.ReadAll(response.Body)
//读取出来的错误信息存在换行符号,调用strings.Trim去除换行符号
body := strings.Trim(string(all), "\n")
if response.StatusCode != exceptedCode || body != exceptedMsg {
t.Errorf("expect (%d, %s); got (%d, %s)", exceptedCode, exceptedMsg, response.StatusCode, body)
}
}
- 通过使用假的response/request进行测试
- 通过起一个服务器进行测试