🧪

【Go】Goのテストに入門してみた! ~一時ディレクトリの作成編~

に公開

はじめに

前回は「環境変数のセット」を見ていきました。
今回は「一時ディレクトリの作成」に入門します!

前回の記事はこちら!

この記事でわかること

  • Goのテストで一時的ディレクトリを作成する方法
  • T.TempDir() の特徴
  • T.TempDir() 以外の一時ディレクトリ作成について

Goのテストで一時ディレクトリを作るには?

Goのテストで、一時的なディレクトリを作成したい場合は、T.TempDir() メソッドを使うことができます。
これはGo 1.15で追加されたメソッドで、ドキュメントには以下のような記載があります。

TempDir returns a temporary directory for the test to use. The directory is automatically removed when the test and all its subtests complete. Each subsequent call to TempDir returns a unique directory; if the directory creation fails, TempDir terminates the test by calling Fatal.

ざっくり要約すると、

  1. 全てのテスト・サブテストが終了すると自動的に削除される
  2. 呼び出すたびに一意のディレクトリを作成する
  3. ディレクトリ作成に失敗すると、その場でテストを終了させる

このような特徴があります。ファイル操作を伴うテストをする場合などで使われます。

T.TempDir()メソッドを使って一時ディレクトリを作成してみよう!

今回は、一時ディレクトリの中にテキストファイルを作成し、その中に書き込みをするケースで実装してみます。

main_test.go
package main

import (
	"os"
	"path/filepath"
	"testing"
)

func TestWriteFile(t *testing.T) {
    tmpDir := t.TempDir()
    
    filepath := filepath.Join(tmpDir, "test.txt")
    content := []byte("Hello TempDir!")
    
    if err := os.WriteFile(filepath, content, 0644); err != nil {
        t.Fatalf("failed to write file: %v", err)
    }
    
    got, err := os.ReadFile(filepath)
    if err != nil {
        t.Fatalf("failed to read file: %v", err)
    }
    if string(got) != string(content) {
        t.Errorf("got %q, want %q", got, content)
    }
}

実行すると、以下のような結果が得られます。

ターミナル
# go test -v

=== RUN   TestWriteFile
--- PASS: TestWriteFile (0.00s)
PASS
ok      go-test-practice        0.489s

B.TempDir()メソッドとF.TempDir()メソッドとは?

先ほどは、T.TempDir() メソッドを使って一時的なディレクトリを作成しました。
これはユニットテストでの一時的ディレクトリ作成で使われるものです。
ユニットテスト以外に一時的なディレクトリを作成するには、B.TempDir()F.TempDir() を使います。

B.TempDir()

これはベンチマークテストで一時的にディレクトリを作成する必要がある時に使われます。

main_test.go
func BenchmarkWriteFile(b *testing.B) {
    // ベンチマークテスト用の一時的なディレクトリ
    dir := b.TempDir()
    filePath := filepath.Join(dir, "bench.txt")
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        fmt.Println(filePath)
        _ = os.WriteFile(filePath, []byte("benchmark"), 0644)
    }
}

実行すると、以下のような結果が得られます。

ターミナル
# go test -v -benchmem -bench .

=== RUN   TestWriteFile
--- PASS: TestWriteFile (0.00s)
goos: darwin
goarch: arm64
pkg: go-test-practice
cpu: Apple M1
BenchmarkWriteFile
BenchmarkWriteFile-8       31827             39269 ns/op             200 B/op          3 allocs/op
PASS
ok      go-test-practice        1.848s

F.TempDir()

これはFuzzingテストで一時的にディレクトリを作成する必要がある時に使われます。

main_test.go
func FuzzWriteFile(f *testing.F) {
    f.Add("Hello")
    
    f.Fuzz(func(t *testing.T, input string) {
        // Fuzzingテスト用の一時的なディレクトリ
        dir := t.TempDir()
        filePath := filepath.Join(dir, "fuzz.txt")
    
        _ = os.WriteFile(filePath, []byte(input), 0644)
        data, _ := os.ReadFile(filePath)
        if string(data) != input {
            t.Errorf("expected %s, got %s", input, string(data))
        }
    })
}

実行すると、以下のような結果が得られます。

ターミナル
# go test -fuzz FuzzWriteFile -fuzztime 10s

=== RUN   TestWriteFile
--- PASS: TestWriteFile (0.00s)
=== RUN   FuzzWriteFile
fuzz: elapsed: 0s, gathering baseline coverage: 0/1 completed
fuzz: elapsed: 0s, gathering baseline coverage: 1/1 completed, now fuzzing with 8 workers
fuzz: elapsed: 3s, execs: 5633 (1876/sec), new interesting: 2 (total: 3)
fuzz: elapsed: 6s, execs: 8000 (790/sec), new interesting: 2 (total: 3)
fuzz: elapsed: 9s, execs: 10041 (680/sec), new interesting: 2 (total: 3)
fuzz: elapsed: 11s, execs: 10370 (164/sec), new interesting: 2 (total: 3)
--- PASS: FuzzWriteFile (11.01s)
=== NAME  
PASS
ok      go-test-practice        11.340s

まとめ

今回は「一時ディレクトリの作成」について学びました。

  • T.TempDir() はユニットテストで一時ディレクトリを作るときに利用する
  • B.TempDir() はベンチマークテストで一時ディレクトリを作るときに利用する
  • F.TempDir() はFuzzingテストで一時ディレクトリを作るときに利用する

いずれのメソッドも「テストが終了したら自動的にファイルを削除する」という共通点があり、ファイルやディレクトリ操作を伴うテストを安全・シンプルに記述できるのが大きなメリットです。

次回は「スライスとマップの比較テスト」に入門します!

参考

https://pkg.go.dev/testing
https://pkg.go.dev/path/filepath#Join
https://devlights.hatenablog.com/entry/2024/06/07/073000
https://future-architect.github.io/articles/20250509a/#一時ディレクトリを作成したい

Discussion