go語言使用GoConvey框架進行測試
本週作業爲在go-online上完成一個最小堆算法,在完成之後我使用GoConvey進行測試。
要想寫出好的的代碼,必須學會測試框架,對於golang,可以使用自帶的go test
測試,也可以使用其他框架如
GoConvey,GoStub,GoMock,Monkey,本次我學習使用GoConvey。
安裝GoConvey
go get github.com/smartystreets/goconvey
需要等待較長的一段時間,然後查看$GOPATH/src/github.com
目錄下增加了smartystreets
文件夾即可。
使用GoConvey
將作業代碼複製到go工作空間中命名爲myheap.go
,並且在同一目錄下創建myheap_test.go
,
先go build
或者go install
生成包,不需main主函數。因爲要測試的函數需要有返回值,所以簡單修改一下作業中的函數,將nodes返回。
myheap_test.go文件如下:
package myheap
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestInit(t *testing.T) {
Convey("test", t, func() {
nodes := []Node{
Node{3},
Node{6},
Node{9},
Node{1},
Node{2},
Node{5},
Node{8},
Node{4},
Node{7},
}
Convey("Test Init()", func(){
So(Init(nodes), ShouldResemble, []Node{
Node{1},
Node{2},
Node{5},
Node{4},
Node{3},
Node{9},
Node{8},
Node{6},
Node{7},
})
})
nodes = Init(nodes)
Convey("Test Push()", func(){
So(Push(Node{0}, nodes), ShouldResemble, []Node{
Node{0},
Node{1},
Node{5},
Node{4},
Node{2},
Node{9},
Node{8},
Node{6},
Node{7},
Node{3},
})
})
nodes = Push(Node{0}, nodes)
Convey("Test Pop()", func(){
So(Pop(nodes), ShouldResemble, []Node{
Node{1},
Node{2},
Node{5},
Node{4},
Node{3},
Node{9},
Node{8},
Node{6},
Node{7},
})
})
})
}
myheap.go文件如下:
package myheap
import "fmt"
type Node struct {
Value int
}
// 用於構建結構體切片爲最小堆,需要調用down函數
func Init(nodes []Node) []Node{
for i := len(nodes)/2 - 1; i >= 0; i-- {
down(nodes, i, len(nodes))
}
return nodes
}
// 需要down(下沉)的元素在切片中的索引爲i,n爲heap的長度,將該元素下沉到該元素對應的子樹合適的位置,從而滿足該子樹爲最小堆的要求
func down(nodes []Node, i, n int) {
var parent int = i
var child int = i*2+1
var tmp int = nodes[i].Value
for child < n {
//取較小的孩子
if (child < n-1) && (nodes[child].Value > nodes[child+1].Value) {
child++
}
if tmp > nodes[child].Value {
nodes[parent].Value = nodes[child].Value
parent = child
child = parent*2 + 1
} else {
break
}
}
nodes[parent].Value = tmp
}
// 用於保證插入新元素(j爲元素的索引,切片末尾插入,堆底插入)的結構體切片之後仍然是一個最小堆
func up(nodes []Node, j int) {
var child int = j
var parent int = (j-1)/2
var tmp int = nodes[j].Value
for parent >= 0 && child >= 1 {
if tmp < nodes[parent].Value {
nodes[child].Value = nodes[parent].Value
child = parent
parent = (child-1)/2
} else {
break
}
}
nodes[child].Value = tmp
}
// 彈出最小元素,並保證彈出後的結構體切片仍然是一個最小堆,第一個返回值是彈出的節點的信息,第二個參數是Pop操作後得到的新的結構體切片
func Pop(nodes []Node) []Node {
//min := nodes[0]
nodes[0].Value = nodes[len(nodes)-1].Value
nodes = nodes[ :len(nodes)-1]
down(nodes,0,len(nodes)-1)
return nodes
}
// 保證插入新元素時,結構體切片仍然是一個最小堆,需要調用up函數
func Push(node Node, nodes []Node) []Node {
nodes = append(nodes, node)
up(nodes, len(nodes)-1)
return nodes
}
// 移除切片中指定索引的元素,保證移除後結構體切片仍然是一個最小堆
func Remove(nodes []Node, node Node) []Node {
for i := 0; i < len(nodes); i++ {
if node.Value == nodes[i].Value {
nodes[i].Value = nodes[len(nodes)-1].Value
nodes = nodes[:len(nodes)-1]
down(nodes, i, len(nodes)-1)
}
}
return nodes
}
//用於打印堆
func PrintList(nodes []Node) {
for _, ele := range nodes {
fmt.Printf("%d ", ele.Value)
}
fmt.Printf("\n")
}
進入該目錄並執行go test
即可,與原生命令相同,然後可以看到輸出:
通過:
沒通過:
上面有具體信息