🐕

Go言語を基礎から徹底的に叩き込む〜#4-2 テストコード〜

2024/04/29に公開

概要

この記事の続きです!
Go のテストコードについてです!

Go 言語テストコード

Go は簡単にテストコードが記述できるよう、標準で便利なパッケージ、ツールが用意されている。

テスト関連の標準ライブラリ、ツール

  • ライブラリ
    • testing:テストを作成するための関数を用意してくれている
  • ツール
    • go test:テスト実行とレポート作成をしてくれる

これらがバンドルされているおかげで簡単にユニットテストが作成できる。

Go のテスト基礎

Go のテストには以下のルールがある。

  • コードと同じディレクトリ、同じパッケージにテストコードを置くこと。
  • テストコードのファイル名は*_test.goとする。
    • 例:foo.goに対するテストはfoo_test.goとする。
  • テスト関数の命名はTestから始め、引数に*testing.Tをとる。
// checkHello関数のテスト
func TestCheckHello(t *testing.T) {
}

テスト実行

テスト実行したいファイルがあるディレクトリで以下のコマンド実行

# テストの実行
go test

# テスト結果の詳細も出力
go test -v

# カレントディレクトリとサブディレクトリ以下の全てのパッケージのテストを実行
go test ./...

# テストケースのカバー率を出力
go test -cover

テスト例

以下のように Add 関数がpackage calにある。

package cal

func Add(a, b int) int {
	return a + b
}

このテストコードの例が以下

package cal

import "testing"

var Debug bool = true

func TestAdd(t *testing.T) {
	if Debug {
		t.Skip("Test Skip")
	}
	result := Add(1, 2)
	expected := 3
	if result != expected {
		t.Errorf("Add(1, 2) failed. Expected %d got %d",expected , result)
	}
}

テーブルドリブンテスト

実際に使われるコードのテストが 1 ケースで終わることはほとんどないでしょう。
例えば以下のような Div 関数が存在したとする。

package cal

import "fmt"

func Div(a, b int) (int, error) {
	if b == 0 {
		return 0, fmt.Errorf("0除算エラー b: %d", b)
	}
	return a / b, nil
}

ざっと見ただけでも正常系のテストケースとb=0を渡したエラーケースのテストが必要になる。

今回は以下のテストケースをチェックしたいとする。

  • 正常系
    • 割り切れるケース(a=6, b=3)
    • 割り切れないケース(a=10 b=3)
  • 異常系
    • 0 除算ケース(a=6, b=0)

このように数ケースチェックしたい場合に、全てのケースを毎回作っていると面倒になる。(テストが面倒になると作成されなくなる。or 形だけになるのでなるべく負荷を軽くしたい)
テーブルドリブンテストは以下のように構造体でテストケースを定義することで、メンテナンスとテストケースの追加を容易にしてくれる。

type divTestCase struct {
	a, b           int
	expectedResult int  //期待値
	expectedError  bool //エラーが発生するケース:true
}

func TestDiv(t *testing.T) {
	testCases := []divTestCase{
		{a: 6, b: 3, expectedResult: 2, expectedError: false},
		{a: 10, b: 3, expectedResult: 3, expectedError: false},
		{a: 6, b: 0, expectedResult: 0, expectedError: true},
	}

	for _, tc := range testCases {
		result, err := Div(tc.a, tc.b)
		if tc.expectedError {
			// エラーを期待するケース
			if err == nil {
				t.Errorf("Div(%d, %d) faild. エラーを期待していましたが、err == nilでした", tc.a, tc.b)
			}
		} else {
			if err != nil {
				t.Errorf("Div(%d, %d) faild. エラーを期待していませんでしたが、次のエラーを取得: %s", tc.a, tc.b, err)
			}
		}
		if result != tc.expectedResult {
			t.Errorf("Div(%d, %d) faild. 期待値:%d, 取得値:%d", tc.a, tc.b, tc.expectedResult, result)
		}
	}
}

まとめ

簡単でしたが、今回も以上とします。
次回は Web 開発で必要なライブラリについて見ていきたいと思います。

GitHubで編集を提案

Discussion