Help us understand the problem. What is going on with this article?

GAEでテストをする話

More than 3 years have passed since last update.

はじめに

基本的に以下の記事を参考にして書いています。
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
に作ったメソッドを試しにやってみる。

テストファイル

DataStoreManager_test.go
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ファイル

VilidateData.go
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
}

//テストされる側のファイル

DataStoreManager.go
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というメソッドはややこしいが、値に対して想定外のエラーがでたかどうかを判定するメソッドである。

結果

テストが通った時

terminal.bash
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がもらえる。

CST_negi
Luppet開発とLuppet Cafeの技術監修をやってます。
https://negipoyoc.com/
showroom
SHOWROOMは、アイドルやアーティストとインターネット上でコミュニケーションが楽しめるライブ動画ストリーミングプラットフォームです。
https://www.showroom-live.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away