Carpe Diem

備忘録

Bazelで他パッケージのテストファイルを参照したい

背景

Bazelでは次のようなディレクトリ構成で、

.
├── package_a
│   ├── a.go
│   ├── a_test.go
│   └── test.yaml
└── package_b
    ├── b.go
    └── b_test.go

パッケージAのファイルtest.yamlをパッケージBのテストで参照したい時に、

go_test(
    name = "b_test",
    srcs = ["b_test.go"],
    deps = ["//path/to/package_a:package_a_lib"],
    data = ["//path/to/package_a"],
)

としても、直接は参照できないです。

今回はその解決方法です。

環境

  • Bazel v7.2.0

原因

参照できないときの主な原因は2つあります。

  • 該当ファイルにvisibilityが設定されてないのでprivate扱いになっている
  • Bazelのターゲットとして参照できるようになっていない

方法

対応方法は2種類あります。

  1. exports_filesを使う
  2. filegroupを使って公開する

具体例

次のようなディレクトリ構造だとします。

.
├── BUILD.bazel
├── MODULE.bazel
├── MODULE.bazel.lock
├── Makefile
├── WORKSPACE
├── fizzbuzz
│   ├── BUILD.bazel
│   ├── fizzbuzz.go
│   ├── fizzbuzz_test.go
│   └── testdata
│       └── golden.txt
├── fizzbuzz2
│   ├── BUILD.bazel
│   ├── fizzbuzz.go
│   └── fizzbuzz_test.go
├── go.mod
└── go.sum

fizzbuzz2/fizzbuzz_test.goではfizzbuzz/testdata/golden.txtを使いたいとします。

fizzbuzz2/fizzbuzz_test.go自体は

package fizzbuzz2

import (
    "os"
    "strings"
    "testing"
)

func TestFizzBuzz(t *testing.T) {
    goldenFile := "../fizzbuzz/testdata/golden.txt"
    expectedOutput, err := os.ReadFile(goldenFile)
    if err != nil {
        t.Fatalf("failed reading golden file: %s", err)
    }

    expectedLines := strings.Split(string(expectedOutput), "\n")
    for i := 1; i < len(expectedLines); i++ {
        expected := expectedLines[i-1]
        actual := FizzBuzz(i)
        if actual != expected {
            t.Errorf("FizzBuzz(%d) = %s; want %s", i, actual, expected)
        }
    }
}

相対パスで参照しており、

$ go test ./...
ok      github.com/jun06t/bazel-sample/testfile/fizzbuzz
ok      github.com/jun06t/bazel-sample/testfile/fizzbuzz2

が通る状態ですが、そのままだとBazelでは以下のエラーが出ます。

//fizzbuzz:fizzbuzz_test                                                 PASSED in 0.5s
//fizzbuzz2:fizzbuzz2_test                                               FAILED in 0.3s

a. exports_files

exports_filesを使ってターゲットを用意する方法です。

fizzbuzz/BUILD.bazel

ファイルがある方のBUILD.bazelで、exports_filesを使ってファイルを参照可能にします。

load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
    name = "fizzbuzz",
    srcs = ["fizzbuzz.go"],
    importpath = "github.com/jun06t/bazel-sample/testfile/fizzbuzz",
    visibility = ["//visibility:public"],
)

go_test(
    name = "fizzbuzz_test",
    srcs = ["fizzbuzz_test.go"],
    data = ["testdata/golden.txt"],
    embed = [":fizzbuzz"],
)

exports_files(["testdata/golden.txt"])  # ここ

fizzbuzz2/BUILD.bazel

ターゲットが公開されたら参照します。

load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
    name = "fizzbuzz2",
    srcs = ["fizzbuzz.go"],
    importpath = "github.com/jun06t/bazel-sample/testfile/fizzbuzz2",
    visibility = ["//visibility:public"],
)

go_test(
    name = "fizzbuzz2_test",
    srcs = ["fizzbuzz_test.go"],
    embed = [":fizzbuzz2"],
    data = ["//fizzbuzz:testdata/golden.txt"],  # ここ
)

動作確認

$ bazel test //...
//fizzbuzz:fizzbuzz_test                                        (cached) PASSED in 0.5s
//fizzbuzz2:fizzbuzz2_test                                               PASSED in 0.1s

通るようになりました。

b. filegroup

次はfilegroupを使ってターゲットを用意する方法です。

fizzbuzz/BUILD.bazel

load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
    name = "fizzbuzz",
    srcs = ["fizzbuzz.go"],
    importpath = "github.com/jun06t/bazel-sample/testfile/fizzbuzz",
    visibility = ["//visibility:public"],
)

go_test(
    name = "fizzbuzz_test",
    srcs = ["fizzbuzz_test.go"],
    data = [":test_dir"],  # ここ
    embed = [":fizzbuzz"],
)

# ここ
filegroup(
    name = "test_dir",
    srcs = glob(["testdata/**"]),
    visibility = ["//visibility:public"],
)

exports_fileと違ってfilegroupは複数のファイルをまとめてターゲットに登録できます。

fizzbuzz2/BUILD.bazel

ターゲットが公開されたら参照します。

load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
    name = "fizzbuzz2",
    srcs = ["fizzbuzz.go"],
    importpath = "github.com/jun06t/bazel-sample/testfile/fizzbuzz2",
    visibility = ["//visibility:public"],
)

go_test(
    name = "fizzbuzz2_test",
    srcs = ["fizzbuzz_test.go"],
    embed = [":fizzbuzz2"],
    data = ["//fizzbuzz:test_dir"],  # ここ
)

動作確認

$ bazel test //...
//fizzbuzz:fizzbuzz_test                                                 PASSED in 0.5s
//fizzbuzz2:fizzbuzz2_test                                               PASSED in 0.3s

その他

サンプルコード

今回のサンプルコードはこちら

github.com

まとめ

Bazelのテストで他パッケージのファイルを参照する方法を紹介しました。

参考