初めての技術記事書いてみます。
最近Goを業務で書き始めた初心者なので、あたたかく見守ってください。
状況
GoMockを使ったテストコードを書いてると、以下のようなGomockのエラーに遭遇しました。
sample.go:17: Unexpected call to *mock_sample.MockSample.Process([2025-04-08 00:00:00 +0900 JST]) at sample/sample.go:17 because:
expected call at C:/Users/fuuta/Documents/home/program/study-go/app/sample/sample_test.go:34 doesn't match the argument at index 0.
Got: 2025-04-08 00:00:00 +0900 JST (time.Time)
Want: is equal to 2025-04-08 00:00:00 +0900 JST (time.Time)
抜粋してみると完全に一致していることがわかります。
Got: 2025-04-08 00:00:00 +0900 JST (time.Time)
Want: is equal to 2025-04-08 00:00:00 +0900 JST (time.Time)
原因
「何が違うねん!?」と最初思いましたが、どうやらTime型のフィールドの一つであるLocationが異なるようでした。
今回の例においては Local
と Asia/Tokyo
とで二つのLocation構造体があり、Got側とwant側で日時は同じだが異なるLocationを持ったTime構造体の比較を行っていたのが原因でした。
テスト落ちの出力で JST
表記になっている原因は、LocationにLocalが指定されていると日本にいる場合は JST
と出る仕組みなんだろうと推測してます。
最後に簡単な検証用ソースを添付しておきます。
sample_test.go
package sample
import (
"fmt"
"test/mock_sample"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)
// gomock使った検証用
func Test1(t *testing.T) {
location, _ := time.LoadLocation("Local")
layout := "2006-01-02 15:04:05"
value := "2025-04-08 00:00:00"
time1, _ := time.ParseInLocation(layout, value, location)
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := mock_sample.NewMockSample(ctrl)
m.EXPECT().Process(time1)
Process(m)
}
// gomock使わない検証用
func Test2(t *testing.T) {
locationLocal, _ := time.LoadLocation("Local")
locationJST, _ := time.LoadLocation("Asia/Tokyo")
layout := "2006-01-02 15:04:05"
value := "2025-04-08 00:00:00"
time1, _ := time.ParseInLocation(layout, value, locationLocal)
time2, _ := time.ParseInLocation(layout, value, locationJST)
t.Logf("%v\n", time1)
t.Logf("%v\n", time2)
t.Logf("%v\n", time1 == time2)
t.Logf("%v\n", time1.Equal(time2))
t.Logf("%v\n", fmt.Sprintf("%v (%T)", time1, time1))
t.Logf("%v\n", fmt.Sprintf("%v (%T)", time2, time2))
assert.Equal(t, time1, time2)
// expected: time.Date(2025, time.April, 8, 0, 0, 0, 0, time.Local)
// actual : time.Date(2025, time.April, 8, 0, 0, 0, 0, time.Location("Asia/Tokyo"))
}
sample.go
package sample
import "time"
type Sample interface {
Process(time time.Time)
}
func Process(sample Sample) {
location, _ := time.LoadLocation("Asia/Tokyo")
layout := "2006-01-02 15:04:05"
value := "2025-04-08 00:00:00"
time, _ := time.ParseInLocation(layout, value, location)
sample.Process(time)
}
Test2
の方を見ると分かりますが、 testify/assert
の assert.Equal
を使うとTime型も構造体としてフィールド単位で出力してくれるので違いが明確にわかります。
Gomock
は"%v"で出力する実装となっており、この場合Time型固有のフォーマットで出力されます。普段は見やすいものの今回はそれが裏目に出た形ですね。
まとめ
どの言語も日付周りは厄介ですね。。。