ScalaのビルドツールであるMillでテストを書こうとしたらsbtとディレクトリ構成が違っていて詰まっていたのでその違いを記しておく。
% mill --version Mill Build Tool version 0.11.2 Java version: 18.0.2, vendor: Amazon.com Inc., runtime: /home/windymelt/.asdf/installs/java/corretto-18.0.2.9.1 Default locale: ja_JP, platform encoding: UTF-8 OS name: "Linux", version: 6.3.9-1-default, arch: amd64
おさらい: sbtでテストを書くときのディレクトリ構成
sbtではテストはsrc/test/にソースコードを配置する。
└── (project root)
└── src
├── main
└── test
testのソースコードではtestコンフィギュレーションを指定したライブラリがクラスパスに導入され、テストフレームワークが利用できるようになる。
コンフィギュレーションについては拙著の記事を参照。
Millでテストを書くときのディレクトリ構成
Millにはテストコンフィギュレーションというものが存在しない。このことはドキュメントにも何度も書いてある。
ではどうやって「テストのときだけ依存するライブラリ」を表現するかというと、本体モジュールの下にテストモジュールをネストさせることで、本体モジュールの依存性をテストモジュールに引き継がせる。
ビルド定義は以下のようになる:
import mill._, scalalib._ // トップレベルのモジュール。本体の実装がある object app extends RootModule with ScalaModule { def scalaVersion = "3.3.0" def publishVersion = "0.1.0-SNAPSHOT" // appの下にtestモジュールを配置する。ここでmunitに依存する object test extends ScalaTests with TestModule.Munit { def ivyDeps = Agg(ivy"org.scalameta::munit::0.7.29") } }
2つの原則さえ覚えておけば役に立つ。1. Millではモジュールはそのままディレクトリになる。2. ソースコードはモジュールディレクトリのsrcディレクトリに置く。これに加えて、RootModuleを継承しているモジュールはモジュールディレクトリを省略してそのままsrcディレクトリを置ける。今回の場合は、appがRootModuleを継承しているのでそのままsrc/ディレクトリを置き、その下にあるtestモジュールのためにtestディレクトリを置く。
└── (project root)
├── src
│ └── Foo.scala
└── test
└── src
└── FooSuite.scala
ディレクトリ構成は上掲のようになる。
sbtからの差分
sbtからMillに入ってきた人は、以下の点に注意する必要がある:
srcの下にmainやtestディレクトリは存在しない- Millでは直接パッケージ階層が始まる。
- テストコードは、テスト対象のモジュールにネストしたモジュールとして構成する
- ネストすると依存性を引き継げる
ビルドしたい単位がそのままディレクトリになるという設計思想さえ覚えておけば、あまり難しくはない。sbtでは1つにまとめられているが、Millではそのように扱わない。
これを知らなかったため、[E006] Not Found Errorがたくさん出て困ってしまった。テストライブラリを入れてるのにな〜と思っていたところ、そもそもディレクトリ構成の作法も別だったというだけの話だった。ビルドツールが違えばディレクトリ構成も変わる。よく考えれば当たり前だ。