Go
test
echo

Golangのtestify/assert 使えそうな関数まとめ

Introduction

最近Echoでサーバーを書く機会があった。
テストコードを書きたかった。
Echo Document Testingを見てみると

import (
    "net/http" //<- わかる
    "net/http/httptest" //<- わかる
    "strings" //<- わかる
    "testing" //<- 超わかる

    "github.com/labstack/echo" //<- わかる
    "github.com/stretchr/testify/assert" //<-なにこれ????
)

github.com/stretchr/testify/assertとか言うのかimportされていた

もう少し見てみると

func TestCreateUser(t *testing.T) {
    // Setup
    e := echo.New()
    req := httptest.NewRequest(echo.POST, "/", strings.NewReader(userJSON))
    req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)
    h := &handler{mockDB}

    // Assertions
    if assert.NoError(t, h.createUser(c)) {
        assert.Equal(t, http.StatusCreated, rec.Code)
        assert.Equal(t, userJSON, rec.Body.String())
    }
}

「なるほど。 assertはRubyのvalidation的な立ち位置か。公式README読み行こ。」

「日本語版ないな」「和訳されたやつないかな」

Google[testify assert][Search]

「うんないな。書こう」

そんな経緯です、。ゆるく検証していきます

環境

go 1.9
assert 1.2.1

記載されている結果はすべて上記の環境により実行しております

比較

func ElementsMatch(リストの比較)

func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool)

ElementMatchはlistA(array, slice...) とlistB(array, slice...)の要素が一致しているか判定します (順序は問わない)

assert.ElementMatch(t, [...]int{1,2}, [...]int{1, 2} ) //-> Success

assert.ElementMatch(t, [...]int{1,2}, [...]int{2, 1} ) //-> Success

assert.ElementMatch(t, [...]int{1,2}, [...]int{1} ) //-> Failed

assert.ElementMatch(t, [...]int{1,2}, [...]int{1, 3} ) //-> Failed


func Equal(比較検証)

func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool

2つのオブジェクトを比較します

assert.Equal(t, 123, 123) //-> Success
assert.Equal(t, 123, 321) //-> Failed

assert.Equal(t, "123", "123") //-> Success
assert.Equal(t, "123", "321") //-> Failed

assert.Equal(t, [...]int{1}, [...]int{1}) //-> Success
assert.Equal(t, [...]int{1}, [...]int{2}) //-> Failed

func Exactly(厳密な比較検証)

func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool

厳密な比較検証します

assert.Exactly(t, int32(123), int64(123)) //-> Failed
assert.Exactly(t, int32(123), uint32(123)) //-> Failed
assert.Exactly(t, int32(123), 123) //-> Failed
assert.Exactly(t, "123", 123) //-> Failed

assert.Exactly(t, 123, 123) //-> Success

//------------------------------------
import "strconv"
assert.Exactly(t strconv.Itoa(123), "123") //-> Success

func JSONEq(JSONが同等であるか検証)

func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool

JSONは2つのJSONが同等であるか検証。こちらも順序は問わないみたいですね

assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"hello": "world", "foo": "bar"}`) //-> Success

assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) //-> Success

assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world!"}`) //-> Failed

assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello!": "world"}`) //-> Failed

assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello!": "world""}`) //-> Failed(Syntax Error)

func EqualError(Errorを比較)

func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool

EqualErrorは、ある関数がエラーを返し(error)
それが提供されたエラー(String)と等しいことを検証します。

import "errors"

// errors.New() は Errorの作成
assert.EqualError(t, errors.New("HOGE"), "HOGE") //-> Success
assert.EqualError(t, errors.New("HOGE"), "FUGA") //-> Failed

func EqualValues

func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool

等しい値は、2つのオブジェクトが等しいか、同じ型に変換可能であり、等しいことを示します。

assert.EqualValues(t, uint32(123), int32(123)) //-> Success
assert.EqualValues(t, 123, int32(123)) //-> Success

assert.EqualValues(t, string(123), int32(123)) //-> Success

func IsType(同じ型であるか検証)

func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool

2つの構造体が同じ型であることを検証します

type (
    User struct {
        ID   int
        Name string
        Age  int
        Have Have
    }
    Have struct {
        toy   bool
        drink bool
        bag   bool
    }
)
user1 := User{1, "Plata", 17, Have{true, false, true}}
user2 := User{2, "aznalo", 17, Have{false, false, true}}
have  := Have{true, false, true}
//----------------------------------------------------

assert.IsType(t, user1, user1) //-> Success

assert.IsType(t, user1, user2) //-> Success

assert.IsType(t, user1, new(User)) //-> Failed

assert.IsType(t, user1, new(Have)) //-> Failed

assert.IsType(t, user1, have) //-> Failed

Error*

func Error(Errorが返却されるか検証)

func Error(t TestingT, err error, msgAndArgs ...interface{}) bool

関数がErrorを返却することを検証

import "errors"

// errors.New() は Errorの作成
assert.Error(t, errors.New("HOGE")) //-> Success
assert.Error(t, nil) //-> Failed

func NoError(エラーが無いことを検証)

func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool
import "errors"

assert.NoError(t, nil) //-> Success
assert.Error(t, errors.New("HOGE")) //-> Failed

func Fail(Fieldさせる)

Fieldを発生させます

func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool
assert.Fail(t, "HOGE") //->
/*--- FAIL: TestXxxx (0.03s)
        Error Trace:    xxx_test.go:xx
        Error:          HOGE
        Test:           TestXxxx
*/

func FailNow

func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool

func Failと差がわからない

assert.FailNow(t, "HOGE") //->
/*--- FAIL: TestXxxx (0.03s)
        Error Trace:    xxx_test.go:xx
        Error:          HOGE
        Test:           TestXxxx
*/

func FileExists(ファイルのパスが存在するか検証)

func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool

指定されたパスにファイルが存在するかどうかをチェックします。またディレクトリを指定した場合は失敗します

assert.FileExists(t, "/go/src/app/controllers/API/main.go") //-> Success

assert.FileExists(t, "/go/src/app/controllers/API") //-> Failed

assert.FileExists(t, "/go/src/app/controllers/API/bash") //-> Failed

存在を検証

func Empty(値が空か検証)

func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool

Objectが空であることを判定します。
nil""false0、またはlen == 0のスライスは検証は成功します

assert.Empty(t, nil) //-> Success

assert.Empty(t, 0) //-> Success
assert.Empty(t, 1) //-> Failed

assert.Empty(t, "") //-> Success
assert.Empty(t, "Qiita") //-> Failed

assert.Empty(t, [...]int{}) //-> Success
assert.Empty(t, [...]int{1}) //-> Failed
//--------------------------------------
type User struct {
  Name string
}
test := User{}
assert.Empty(t, test) //-> Success

func False(検証対象がFalseか検証*)

func False(t TestingT, value bool, msgAndArgs ...interface{}) bool
assert.False(t, false) //-> Success
assert.False(t, true) //-> Failed

また同じような挙動の関数に func Truefunc Nillがあります

func Len(リストの要素数の検証)

func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool
assert.Len(t, [...]int{1,2,3}, 3) //-> Success
assert.Len(t, [...]int{1,2,3}, 4) //-> Failed

assert.Len(t, [...]string{"1","2","3"}, 3) //-> Success
assert.Len(t, [...]string{"1","2","3"}, 4) //-> Failed

func Contains(含まれることを検証)

func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool
assert.NotContains(t, "Hello World", "Earth") //-> Failed
assert.NotContains(t, [...]string{"Hello", "World"}, "Earth")//-> Failed
assert.NotContains(t, "Hello", "World")//-> Failed

assert.NotContains(t, "HelloWorld", "World")//-> Success
assert.NotContains(t, "Hello World", "World")//-> Success
assert.NotContains(t, [...]string{"Hello", "World"}, "World")//-> Success

func NotContains(含まれないことを検証)

func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool

NotContainsは、指定された文字列、list(array、slice ...)またはmapに、指定された部分文字列または要素が含まれていないことを検証

assert.NotContains(t, "Hello World", "Earth") //-> Success
assert.NotContains(t, [...]string{"Hello", "World"}, "Earth")//-> Success
assert.NotContains(t, "Hello", "World")//-> Success

assert.NotContains(t, "HelloWorld", "World")//-> Failed
assert.NotContains(t, "Hello World", "World")//-> Failed
assert.NotContains(t, [...]string{"Hello", "World"}, "World")//-> Failed

やってみて

Documentに書いてある関数多すぎて全部目を通すのにやっとった