Daje on narzędzia do prostego testowania i uruchamiania tychże testów. Są proste, a jednocześnie dość efektowne, jak cały język.
W niniejszym wpisie postaram się wyłożyć prosty przykład Gophowego pakietu wraz z klasą i przykładami testów.
Po pierwsze, tworzymy pakiet strdict, a w nim tworzymy Gopherowy typ Dict wraz z jego metodami.
Wszystko to zapisujemy w pliki strdict.go w katalogu GOPATH/src/strdict.
--------------
package strdict
import (
"fmt"
)
// new type
type Dict map[string]string
// get value with key
// if key not present then raise panic
func(m Dict) Get(key string) string {
k, ok := m[key]
if !ok{
panic(fmt.Sprintf("No key '%s' in Dict", key))
}
return k
}
// get value with key
// if key not present then return def
func(m Dict) GetDef(key, def string) string {
k, ok := m[key]
if !ok{
return def
}
return k
}
// check if m has key value
func (m Dict) HasKey(key string) bool{
_, ok := m[key]
return ok
}
// set value with key
func(m Dict) Set(key, value string) {
m[key] = value
}
// print all keys and values
func (m Dict) Print(){
for k, v := range(m){
fmt.Println(k, " ", v)
}
}--------------
Teraz tworzymy plik z testami do pakietu. Nazywamy go strdict_test.go i zapisujemy w tym samym katalogu co strdict.go.
--------------
package strdict
import (
"testing"
"fmt"
)
func TestSet(t *testing.T){
m1 := Dict{}
m2 := Dict{}
m1.Set("a", "a")
m1.Set("a", "b")
m1.Set("a", "v")
m1.Set("d", "f")
m2.Set("a", "zzz")
if m1["a"] != "v"{
t.Error("Set error. No value in map")
}
}
func TestGet(t *testing.T){
m := make(Dict)
m["a"] = "b"
m["b"] = "c"
m["c"] = "d"
if m.Get("a") != "b"{
t.Error("Get error. Wrong value for key ")
}
defer func(){
if err := recover(); err == nil{
t.Error("Get error. Getting non existing value should raise panic")
}
}()
m.Get("non existing key")
}
func TestHasKey(t *testing.T){
m := make(Dict)
m["a"] = "a"
m["b"] = "b"
if !m.HasKey("a"){
t.Error("Error checking existing key")
}
if m.HasKey("c"){
t.Error("Error checking none existing key")
}
}
func ExampleGet(){
m := Dict{}
m["a"] = "123"
fmt.Println(m.Get("a"))
//Output:
// 123
}
func BenchmarkGet(b *testing.B){
b.StopTimer()
m := Dict{}
m["aa"] = "aa"
b.StartTimer()
for i := 0; i < b.N; i++ {
_ =m.Get("aa")
}
}
func BenchmarkSet(b *testing.B){
b.StopTimer()
m := Dict{}
b.StartTimer()
for i := 0; i < b.N; i++ {
m.Set("aa", "1")
}
}
--------------Parę słów objaśniających testy:
TestSet, TestGet, TestHasKey - klasyczne przykłady testów jednostkowych. Ich nazwy muszą rozpoczynać się od Test...
W tym jednak wypadku nie mamy instrukcji assert, lecz używamy instrukcji if i t.Error().
ExampleGet - ta funkcja testująca porównuje wyjście standardowe, czyli w tym przypadku wynik instrukcji fmt.Println ze spodziewanym wyjściem które umieściliśmy w komentarzu. Jeśli będą różne wówczas testy zakończą się niepowodzeniem. Musi się zaczynać od Example.
Innymi ciekawymi przykładami są funkcje BenchmarkSet i BenchmarkGet. Mierzą one średni czas wykonania operacji.
Sposób wywołania testów w konsoli:
----------------------------------------------------------------------------
user@user-home:~$ go test strdict
ok strdict 0.006s
----------------------------------------------------------------------------
Sposób wywołania testów wraz z benchmarkami:
----------------------------------------------------------------------------
go test -test.bench="." strdict
PASS BenchmarkGet 20000000 109 ns/op BenchmarkSet 20000000 114 ns/op ok strdict 4.718s
----------------------------------------------------------------------------