今川館

都内勤務の地味OLです

テストで誤差を許容するアサーション assert.InEpsilon と assert.InDelta

追記: InDeltaというもっと簡単に使えるメソッドがあった

assert.InDelta(t, 37500, 38000, 500.0) // ok
assert.InDelta(t, 37500, 38001, 500.0) // Max difference between 37500 and 38001 allowed is 500, but difference was -501

Goのassertモジュール

ユニットテストを書くときにassertモジュールを使っていて、テスト対象物実行した結果が100であることを確かめる場合は

assert.Equal(t, 100, result)

と書けばよいけど、「結果は99.8〜100.2の間で、だいたい100になる」みたいなチェックをするときは当然ながらEqualは使えない。

assert.InEpsilonというメソッドがある

そういうときはassertにはInEpsilonというメソッドが使えるらしい。

https://godoc.org/github.com/stretchr/testify/assert#InEpsilon

InEpsilon asserts that expected and actual have a relative error less than epsilon

Returns whether the assertion was successful (true) or not (false).

float64の引数epsilonに許容誤差を指定して使う。

やってみた

戻り値のxとyが3:1でだいたい500を限界にずれる関数を作る。

package epsilon

import "math/rand"

func Foo() (x, y int) {
	d := rand.Intn(500)
	return 37500 - d, 12500 + d
}

これをInEpsilon使ってテスト。

package epsilon

import (
	"math/rand"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func TestEpsilon(t *testing.T) {
	for i := 0; i < 10000; i++ {
		x, y := Foo()
		assert.InEpsilon(t, 37500, x, 0.014)
		assert.InEpsilon(t, 12500, y, 0.041)
	}
}
許容した誤差を超えてしまった場合
assert.InEpsilon(t, 37500, x, 0.01)

などと誤差を狭めるとこういうメッセージが出てテストが失敗します。

        Error Trace:    epsilon_test.go:18
	Error:      	Relative error is too high: 0.01 (expected)
	            	        < 0.01176 (actual)