#はじめに
基本的に以下の記事を参考にして書いています。
http://qiita.com/sinmetal/items/79458af94e35d7523a50
自分用のメモ書き程度です。
#気をつけること
##ファイル構成
goapp testコマンドでテストを始めるのだが、
その際goapp testで指定したディレクトリにtestコードがないとテストができない。
##テストコード(テストファイル)について
テストファイルとして認識されるためには、様々な制約がある。
####①hoge_test.goというファイル名にする
例:)DatastoreManager_test.go
####*②TestHogefuga(t testing.T){}という形式で書かれたメソッドがある
testHogefugaではダメ、Testhogefugaでもダメ。
TestPutSaveData(t *testing.T)→◯
testPutSaveData(t *testing.T)→×
TestputSaveData(t *testing.T)→×
ということです。
メソッド名 | テストとして認識されるか |
---|---|
TestPutSaveData(t *testing.T) | ◯ |
TestPutSaveData() | × |
testPutSaveData(t *testing.T) | × |
TestputSaveData(t *testing.T) | × |
####③エラーが起きた時にt.Fail()を行うこと
t.Failやt.Fatallnなど、とにかくエラーが起きた時にそれをテスト失敗として見なすように書かないとエラーが捕まえられずテストの意味がない(テストに通ったものとして扱われてしまう)。
####④テストするメソッドにはappengine.NewContextではなくaetest.NewContextを使う
c := appengine.NewContext(g.Request)
なんて書いてあるところを
c,done,err := testcontext()とか書けばおk
####⑤テストが終了するようにdefer done()をする。
c,done,err := testcontext()
という宣言をすることになるけど終了処理ということでdefer done()というのを書いておけばおk
#テストを書いてみよう
http://qiita.com/CST_negi/items/aa7a8ecc950c857fde79
に作ったメソッドを試しにやってみる。
テストファイル
func TestPutSaveData(t *testing.T) {
c, done, err := aetest.NewContext()
if err != nil {
t.Fatal(err)
}
defer done()
testIDCase := map[string]bool{"25": true, "-1": false, "s": false, "5.0": false, "100000000000000000000": true}
testValueCase := map[string]bool{"(5,4,4)": true, "(24.5245,34242.52452,245545.54)": true, "(,,)": false, "3,4,5": false, "(-1)": false}
for key, value := range testIDCase {
log.Println(key, value)
if err := DataStoreManager.PutSaveData(key, "(1,1,1)", c); checkValidityOfError(err, value) {
t.Fatalf("Error Occured %v : data = %s", err, key)
}
}
for key, value := range testValueCase {
log.Println(key, value)
if err := DataStoreManager.PutSaveData("1", key, c); checkValidityOfError(err, value) {
t.Fatalf("Error Occured %v : data = %s", err, key)
}
}
}
func checkValidityOfError(err error, flag bool) bool {
//正しいデータであればerr==nilはTrueだし、正しくないデータであればfalse
//バリデーションがおかしい時は(err == nil) != flagはTrueとなるので
//このメソッドはテストした値に対して自分の意図とは違う状態になった時Trueになる。
return (err == nil) != flag
}
テストをアシストするValidationファイル
package DataStoreManager
import (
"errors"
"regexp"
)
type (
ValidateMode struct {
checkInt bool
checkVector3 bool
}
)
func ValidateData(data string, mode ValidateMode) error {
if mode.checkInt {
if isInt, err := regexp.MatchString("^[0-9]+$", data); err != nil {
return err
} else if !isInt {
return errors.New("Error : this is not int")
}
}
if mode.checkVector3 {
if isVec3, err := regexp.MatchString("^\\((\\d+(\\.\\d+)?,){2}(\\d+(\\.\\d+)?)\\)$", data); err != nil {
return err
} else if !isVec3 {
return errors.New("Error : this is not Vec3")
}
}
return nil
}
//テストされる側のファイル
func PutSaveData(userID string, positionData string /*,g *gin.Context*/, testcontext context.Context) error {
//c := appengine.NewContext(g.Request)
c := testcontext
if err := ValidateData(userID, ValidateMode{true, false}); err != nil {
return err
}
if err := ValidateData(positionData, ValidateMode{false, true}); err != nil {
return err
}
saveTime := time.Now()
if userID == "" {
userID, _ = AllocateID(c, "SaveData")
}
saveKey := datastore.NewKey(c, "SaveData", userID, 0, nil)
saveData := SaveData{UserID: userID, PositionData: positionData, SaveTime: saveTime}
if _, err := datastore.Put(c, saveKey, &saveData); err != nil {
log.Fatalf("Error Occured3: %v", err)
return err
}
return nil
}
やってることは、datastoreにPutするデータに関してのバリデーションテスト(あとは正常にPutできたかどうかも見る)
Mapで Key:Putする値 Value:正常な値かどうかの真偽値
という風に書くことで、値と正常かどうかを紐付けることができる。
checkValidityOfErrorというメソッドはややこしいが、値に対して想定外のエラーがでたかどうかを判定するメソッドである。
#結果
テストが通った時
5.0 false
100000000000000000000 true
25 true
-1 false
s false
(24.5245,34242.52452,245545.54) true
(,,) false
3,4,5 false
(-1) false
(5,4,4) true
PASS
ok _/Users/user_name/go_appengine/gopath/gae_projects/unity-gae 2.635s
OKがもらえる。