テストの標準的なソース場所は以下のとおりです。
src/test/scala/
内のScalaソースsrc/test/java/
内のJavaソースsrc/test/resources/
内のテストクラスパス用リソースリソースは、java.lang.Class
またはjava.lang.ClassLoader
のgetResource
メソッドを使用してテストからアクセスできます。
主要なScalaテストフレームワーク(ScalaCheck、ScalaTest、specs2)は共通のテストインターフェースの実装を提供しており、sbtで動作させるにはクラスパスに追加するだけです。例えば、ScalaCheckは管理された依存関係として宣言することで使用できます。
lazy val scalacheck = "org.scalacheck" %% "scalacheck" % "1.17.0"
libraryDependencies += scalacheck % Test
Test
は設定であり、ScalaCheckはテストクラスパスにのみ存在することを意味し、メインソースには必要ありません。これはライブラリにとって一般的に良い習慣です。なぜなら、ユーザーは通常、ライブラリを使用するためにテスト依存関係を必要としないからです。
ライブラリ依存関係を定義したら、上記の位置にテストソースを追加し、テストをコンパイルして実行できます。テストを実行するためのタスクはtest
とtestOnly
です。test
タスクはコマンドライン引数を受け付けず、すべてのテストを実行します。
> test
testOnly
タスクは、実行するテスト名の空白区切りのリストを受け付けます。例えば
> testOnly org.example.MyTest1 org.example.MyTest2
ワイルドカードもサポートしています。
> testOnly org.example.*Slow org.example.MyTest1
testQuick
タスクは、testOnly
と同様に、同じ構文を使用してフィルターを示すことで、実行するテストを特定のテストまたはワイルドカードに絞り込むことができます。明示的なフィルターに加えて、次の条件のいずれかを満たすテストのみが実行されます。
タブ補完は、最後のTest/compile
の結果に基づいてテスト名に対して提供されます。これは、新しいソースはコンパイルされるまでタブ補完で使用できず、削除されたソースは再コンパイルされるまでタブ補完から削除されないことを意味します。新しいテストソースは、testOnly
を使用して手動で記述して実行することもできます。
メインソースで使用できるタスクは、一般的にテストソースでも使用できますが、コマンドラインではTest /
をプレフィックスとして付け、ScalaコードではTest /
を使用して参照されます。これらのタスクには以下が含まれます。
Test / compile
Test / console
Test / consoleQuick
Test / run
Test / runMain
これらのタスクの詳細については、実行を参照してください。
デフォルトでは、ログは各テストソースファイルごとに、そのファイルのすべてのテストが完了するまでバッファリングされます。これはlogBuffered
を設定することで無効にできます。
Test / logBuffered := false
デフォルトでは、sbtはビルド内のすべてのテストのJUnit XMLテストレポートを生成し、プロジェクトのtarget/test-reports
ディレクトリに配置します。これはJUnitXmlReportPlugin
を無効にすることで無効にできます。
val myProject = (project in file(".")).disablePlugins(plugins.JUnitXmlReportPlugin)
テストフレームワークへの引数は、--
セパレータに続いて、コマンドラインでtestOnly
タスクに提供できます。例えば
> testOnly org.example.MyTest -- -verbosity 1
ビルドの一部としてテストフレームワーク引数を指定するには、Tests.Argument
で構築されたオプションを追加します。
Test / testOptions += Tests.Argument("-verbosity", "1")
特定のテストフレームワークのみに指定するには
Test / testOptions += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "1")
Tests.Setup
とTests.Cleanup
を使用して、セットアップとクリーンアップアクションを指定します。これらは、() => Unit
型またはClassLoader => Unit
型の関数のいずれかを受け付けます。ClassLoader
を受け取る変種には、テストの実行に使用された(または使用されていた)クラスローダーが渡されます。これにより、テストクラスとテストフレームワーククラスの両方にアクセスできます。
注記:フォーキングする場合、テストクラスを含むClassLoaderは別のJVMにあるため、提供できません。この場合は、
() => Unit
変種のみを使用してください。
例
Test / testOptions += Tests.Setup( () => println("Setup") )
Test / testOptions += Tests.Cleanup( () => println("Cleanup") )
Test / testOptions += Tests.Setup( loader => ... )
Test / testOptions += Tests.Cleanup( loader => ... )
デフォルトでは、sbtはすべてのタスクを並列に、そしてsbt自体と同じJVM内で実行します。各テストはタスクにマッピングされるため、テストもデフォルトで並列に実行されます。特定のプロジェクト内のテストを直列に実行するには:
Test / parallelExecution := false
Test
は、統合テストのみを直列に実行するためにIntegrationTest
で置き換えることができます。異なるプロジェクトのテストは、引き続き同時に実行される可能性があることに注意してください。
名前が「Test」で終わるテストクラスのみを実行する場合は、Tests.Filter
を使用します。
Test / testOptions := Seq(Tests.Filter(s => s.endsWith("Test")))
設定
Test / fork := true
すべてのテストが単一の外部JVMで実行されることを指定します。フォーキングを参照して、フォーキングの標準オプションを設定してください。デフォルトでは、フォークされたJVMで実行されるテストは直列に実行されます。テストがJVMにどのように割り当てられ、それらにどのようなオプションを渡すかをより詳細に制御するには、testGrouping
キーを使用できます。例えば、build.sbtでは
import Tests._
{
def groupByFirst(tests: Seq[TestDefinition]) =
tests groupBy (_.name(0)) map {
case (letter, tests) =>
val options = ForkOptions().withRunJVMOptions(Vector("-Dfirst.letter"+letter))
new Group(letter.toString, tests, SubProcess(options))
} toSeq
Test / testGrouping := groupByFirst( (Test / definedTests).value )
}
単一グループ内のテストは直列に実行されます。同時に実行できるフォークされたJVMの数の制限を、デフォルトで1であるTags.ForkedTestGroup
タグの制限を設定することで制御します。グループがフォークされている場合、実際のテストクラスローダーを使用してSetup
とCleanup
アクションを提供することはできません。
さらに、フォークされたテストは、次の設定を使用して、フォークされたJVM内でオプションで並列に実行できます。
Test / testForkedParallel := true
追加のテスト設定を追加して、別個のテストソースと関連するコンパイル、パッケージング、およびテストタスクと設定を持つことができます。手順は以下のとおりです。
次の2つの例では、これを実演します。最初の例は、統合テストを有効にする方法を示しています。2番目の例は、カスタマイズされたテスト設定を定義する方法を示しています。これにより、プロジェクトごとに複数の種類のテストを定義できます。
次の完全なビルド設定は、統合テストを示しています。
lazy val scalatest = "org.scalatest" %% "scalatest" % "3.2.17"
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val root = (project in file("."))
.configs(IntegrationTest)
.settings(
Defaults.itSettings,
libraryDependencies += scalatest % "it,test"
// other settings here
)
configs(IntegrationTest)
は、事前に定義された統合テスト設定を追加します。この設定は、it
という名前で参照されます。settings(Defaults.itSettings)
は、IntegrationTest設定でコンパイル、パッケージング、およびテストアクションと設定を追加します。settings(libraryDependencies += scalatest % "it,test")
は、scalatestを標準テスト設定と統合テスト設定itの両方に追加します。統合テストのみに依存関係を定義するには、「it,test」ではなく「it」を設定として使用します。標準的なソース階層が使用されます。
src/it/scala
src/it/java
src/it/resources
標準的なテストタスクは使用できますが、IntegrationTest/
をプレフィックスとして付ける必要があります。例えば、すべての統合テストを実行するには
> IntegrationTest/test
または、特定のテストを実行するには
> IntegrationTest/testOnly org.example.AnIntegrationTest
同様に、標準設定はIntegrationTest
設定に対して設定できます。直接指定されていない場合、ほとんどのIntegrationTest
設定はデフォルトでTest
設定に委任されます。例えば、テストオプションが以下のように指定されている場合
Test / testOptions += ...
これらはTest
設定によって取得され、次にIntegrationTest
設定によって取得されます。オプションは、IntegrationTest
設定に配置することで、統合テストのみに追加できます。
IntegrationTest / testOptions += ...
または、:=
を使用して既存のオプションを上書きし、これらを決定的な統合テストオプションとして宣言します。
IntegrationTest / testOptions := Seq(...)
前の例は、カスタムテスト設定に一般化できます。
lazy val scalatest = "org.scalatest" %% "scalatest" % "3.2.17"
lazy val FunTest = config("fun") extend(Test)
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val root = (project in file("."))
.configs(FunTest)
.settings(
inConfig(FunTest)(Defaults.testSettings),
libraryDependencies += scalatest % FunTest
// other settings here
)
組み込みの設定を使用する代わりに、新しい設定を定義しました。
lazy val FunTest = config("fun") extend(Test)
extend(Test)
の部分は、定義されていないFunTest
設定に対してTest
に委譲することを意味します。新しいテスト設定のタスクと設定を追加する行は次のとおりです。
settings(inConfig(FunTest)(Defaults.testSettings))
これは、FunTest
設定にテストと設定のタスクを追加することを意味します。統合テストでも同じ方法で実行できます。実際、Defaults.itSettings
は便宜的な定義です。val itSettings = inConfig(IntegrationTest)(Defaults.testSettings)
。
統合テストセクションのコメントは、IntegrationTest
をFunTest
に、"it"
を"fun"
に置き換えた場合を除いて有効です。たとえば、テストオプションはFunTest
用に具体的に構成できます。
FunTest / testOptions += ...
テストタスクは、fun:
をプレフィックスとして実行します。
> FunTest / test
別々のテストソースセット(とコンパイル)を追加する代わりに、ソースを共有することができます。このアプローチでは、ソースは同じクラスパスを使用して一緒にコンパイルされ、一緒にパッケージ化されます。ただし、構成に応じて異なるテストが実行されます。
lazy val scalatest = "org.scalatest" %% "scalatest" % "3.2.17"
lazy val FunTest = config("fun") extend(Test)
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
def itFilter(name: String): Boolean = name endsWith "ITest"
def unitFilter(name: String): Boolean = (name endsWith "Test") && !itFilter(name)
lazy val root = (project in file("."))
.configs(FunTest)
.settings(
inConfig(FunTest)(Defaults.testTasks),
libraryDependencies += scalatest % FunTest,
Test / testOptions := Seq(Tests.Filter(unitFilter)),
FunTest / testOptions := Seq(Tests.Filter(itFilter))
// other settings here
)
主な違いは次のとおりです。
inConfig(FunTest)(Defaults.testTasks)
)のみを追加し、コンパイルとパッケージングのタスクと設定は追加しません。標準の単体テストを実行するには、test
(または同等のTest / test
)を実行します。
> test
追加された構成(ここでは"FunTest"
)のテストを実行するには、前と同様に構成名をプレフィックスとして付けます。
> FunTest / test
> FunTest / testOnly org.example.AFunTest
この共有ソースアプローチの用途の1つは、並列で実行できるテストと、直列で実行する必要があるテストを分離することです。追加の構成に対して、このセクションで説明した手順を実行します。構成をserial
と呼びましょう。
lazy val Serial = config("serial") extend(Test)
次に、次の方法を使用して、その構成でのみ並列実行を無効にできます。
Serial / parallelExecution := false
並列で実行するテストはtest
で実行され、直列で実行するテストはSerial/test
で実行されます。
JUnit5のサポートは、sbt-jupiter-interfaceによって提供されています。プロジェクトにJUnit Jupiterのサポートを追加するには、プロジェクトのメインのbuild.sbtファイルにjupiter-interfaceの依存関係を追加します。
libraryDependencies += "net.aichler" % "jupiter-interface" % "0.9.0" % Test
そして、project/plugins.sbtにsbt-jupiter-interfaceプラグインを追加します。
addSbtPlugin("net.aichler" % "sbt-jupiter-interface" % "0.9.0")
JUnit4のサポートは、junit-interfaceによって提供されています。プロジェクトのメインのbuild.sbtファイルにjunit-interfaceの依存関係を追加します。
libraryDependencies += "com.github.sbt" % "junit-interface" % "0.13.3" % Test
このページでは、追加のテストライブラリのサポートを追加し、追加のテストレポーターを定義する方法について説明します。(下記で説明されている)sbt
インターフェースを実装することでこれを行います。テストフレームワークの作者であれば、テストインターフェースを提供された依存関係として依存させることができます。あるいは、誰でもインターフェースを別のプロジェクトに実装し、そのプロジェクトをsbt Pluginとしてパッケージ化することで、テストフレームワークのサポートを提供できます。
主要なScalaテストライブラリは、sbtの組み込みサポートを持っています。異なるフレームワークのサポートを追加するには、統一されたテストインターフェースを実装します。
テストフレームワークは、ステータスと結果をテストレポーターに報告します。TestReportListenerまたはTestsListenerのいずれかを実装することで、新しいテストレポーターを作成できます。
プロジェクト定義で拡張機能を使用するには
testFrameworks
設定を変更して、テストフレームワークを参照します。
testFrameworks += new TestFramework("custom.framework.ClassName")
プロジェクト定義でtestListeners
設定を上書きして、使用するテストレポーターを指定します。
testListeners += customTestListener
ここで、customTestListener
はsbt.TestReportListener
型です。