go-cmpで便利なOptionを使って、テスト結果を簡単に比較しよう

Go言語

go-cmpを使ってテスト結果と期待値を比較することができますが、さらにOptionを使うことで色々な比較をすることができるようになります。よく業務でテストを書く時に使うOptionのTipsを紹介していきます。

IgnoreFieldsを使って、特定の項目を比較しない

IgnoreFieldsを使うことで、特定の項目は比較をしないようにすることができます。利用例として、プログラム側で生成するようなIDや作成日、更新日などテストで期待値が固定値にしにくいものはIgnoreFieldsを使って比較されないようにします。

package test

import (
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
)

type User struct {
	ID        int64
	Name      string
	CreatedAt time.Time
}

func TestUser(t *testing.T) {
	now := time.Now()
	user1 := User{
		ID:        20,
		Name:      "太郎",
		CreatedAt: now,
	}
	user2 := User{
		ID:        20,
		Name:      "太郎",
		CreatedAt: now.Add(time.Hour),
	}

	opts := cmp.Options{
		// 比較をしないフィールドを設定
		cmpopts.IgnoreFields(User{}, "CreatedAt"),
	}

	// cmp.Diffの引数にopts...をつけることで、optsで設定したオプションで、比較をする
	if diff := cmp.Diff(user1, user2, opts...); diff != "" {
		t.Errorf("結果で差分が出てます\n %s", diff)
	}
}

実行結果の比較

IgnoreFieldsをオプションに追加しなかった場合

CreatedAtで差分が発生

% go test
--- FAIL: TestUser (0.00s)
    ignore_test.go:36: 結果で差分が出てます
           test.User{
                ID:        20,
                Name:      "太郎",
        -       CreatedAt: s"2024-05-14 19:27:01.020786 +0900 JST m=+0.001027711",
        +       CreatedAt: s"2024-05-14 20:27:01.020786 +0900 JST m=+3600.001027711",
          }
FAIL
exit status 1
FAIL    test/blog/go-cmp/ignore 0.231s

IgnoreFieldsをオプションに追加した場合

エラーなく成功する

% go test
PASS
ok      test/blog/go-cmp/ignore 0.319s

SortSlicesで構造体を比較する

SortSlicesを使うことで、2つのスライス同士をソートして比較ができます。
使用例として、構造体のスライス同士を比較する時に、テストの結果と期待値で中身の順番が違うことがありテストが失敗をしてしまうことがあります。その時にfmt.Sprintf(“%v”, {構造体変数})で構造体を文字列に変えてあげて、SortSlicesを使うことで2つの構造体のスライスが比較できます。

package sort

import (
	"fmt"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
)

type User struct {
	ID        int64
	Name      string
	CreatedAt time.Time
}

type Users []User

func TestUsers(t *testing.T) {
	now := time.Now()
	users1 := Users{
		{
			ID:        20,
			Name:      "太郎",
			CreatedAt: now,
		},
		{
			ID:        30,
			Name:      "士郎",
			CreatedAt: now,
		},
	}

	users2 := Users{
		{
			ID:        30,
			Name:      "士郎",
			CreatedAt: now,
		},
		{
			ID:        20,
			Name:      "太郎",
			CreatedAt: now,
		},
	}

	opts := cmp.Options{
		cmpopts.SortSlices(func(i, j interface{}) bool {
			// interface型を文字に変換にして、比較できるようにする
			return fmt.Sprintf("%v", i) < fmt.Sprintf("%v", j)
		}),
	}

	if diff := cmp.Diff(users1, users2, opts...); diff != "" {
		t.Errorf("結果で差分が出てます\n %s", diff)
	}
}

実行結果の比較

SortSlicesをオプションに追加しなかった場合

順番が違うのでID、Nameで差分が発生している。

% go test
--- FAIL: TestUsers (0.00s)
    sort_test.go:56: 結果で差分が出てます
           sort.Users{
                {
        -               ID:        20,
        +               ID:        30,
        -               Name:      "太郎",
        +               Name:      "士郎",
                        CreatedAt: s"2024-05-14 19:28:30.424131 +0900 JST m=+0.001001234",
                },
                {
        -               ID:        30,
        +               ID:        20,
        -               Name:      "士郎",
        +               Name:      "太郎",
                        CreatedAt: s"2024-05-14 19:28:30.424131 +0900 JST m=+0.001001234",
                },
          }
FAIL
exit status 1
FAIL    test/blog/go-cmp/sort   0.267s

SortSlicesをオプションに追加した場合

エラーなく成功する

 % go test
PASS
ok      test/blog/go-cmp/sort   0.289s

まとめ

今回はgo-cmpのOptionを使って、簡単にテスト結果と期待値を比較する方法について解説をしてきました。
他にもテストやGo言語について以下のような記事を書いてますので、興味あれば読んでもらえたらと思います。

  • テストコードを書く時にあるテストでDBを更新して、その更新が他のテストに影響を与えてエラーが発生してしまう問題の対策
  • Go言語でMockを使ってテストする方法
  • gorutineの同時実行数を効率的に制御する方法
  • Goで空の構造体を使ってメモリ効率の良いコードを実装する方法

【おすすめ記事のリンク】

コメント

タイトルとURLをコピーしました