測試的標準來源位置為
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
)允許使用相同的語法來指示篩選器,將執行的測試篩選為特定的測試或萬用字元。除了明確的篩選器之外,只會執行符合下列其中一個條件的測試
Tab 鍵補全會根據上次 Test/compile
的結果提供測試名稱。這表示,在編譯新來源之前,無法使用新的來源進行 Tab 鍵補全,而刪除的來源在重新編譯之前不會從 Tab 鍵補全中移除。仍然可以手動寫出新的測試來源,並使用 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 的變體會傳遞用於執行測試的類別載入器(或曾經用於執行測試的類別載入器)。它提供對測試類別以及測試框架類別的存取權。
注意:在 forking 時,無法提供包含測試類別的 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 中執行。如需設定 forking 的標準選項,請參閱 Forking。根據預設,在 forked JVM 中執行的測試會依序執行。使用 testGrouping
金鑰,可以更精確地控制如何將測試指派給 JVM 以及要將哪些選項傳遞給這些 JVM。例如,在 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 )
}
單一群組中的測試會依序執行。透過設定 Tags.ForkedTestGroup
標籤的限制(預設值為 1),控制允許同時執行的 forked JVM 數目。在 fork 群組時,無法提供具有實際測試類別載入器的 Setup
和 Cleanup
動作。
此外,使用下列設定,可以在 forked JVM 中選擇性地以平行方式執行 forked 測試
Test / testForkedParallel := true
您可以新增其他測試組態,以擁有不同的測試來源集和相關聯的編譯、封裝,以及測試任務和設定。步驟如下
下列兩個範例示範此操作。第一個範例說明如何啟用整合測試。第二個範例說明如何定義自訂的測試組態。這可讓您為每個專案定義多種類型的測試。
以下完整的建置組態展示了整合測試。
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" 作為組態,而不是 "it,test"。使用標準的來源階層結構
src/it/scala
用於 Scala 來源src/it/java
用於 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
)
主要差異在於
若要執行標準單元測試,請執行 test
(或等效的 Test / test
)
> test
若要執行已加入組態的測試(此處為 "FunTest"
),請如先前一樣加上組態名稱作為前綴
> FunTest / test
> FunTest / testOnly org.example.AFunTest
這種共用來源方法的一個用途是將可以平行執行的測試與必須循序執行的測試分開。對其他組態應用此章節中描述的程序。我們將組態稱為 serial
lazy val Serial = config("serial") extend(Test)
然後,我們可以僅在該組態中使用以下程式碼停用平行執行
Serial / parallelExecution := false
平行執行的測試會以 test
執行,而循序執行的測試會以 Serial/test
執行。
sbt-jupiter-interface 提供對 JUnit5 的支援。若要將 JUnit Jupiter 支援加入到您的專案中,請將 jupiter-interface 依賴項加入到您專案的主要 build.sbt 檔案中。
libraryDependencies += "net.aichler" % "jupiter-interface" % "0.9.0" % Test
並將 sbt-jupiter-interface 外掛程式加入到您的 project/plugins.sbt 中
addSbtPlugin("net.aichler" % "sbt-jupiter-interface" % "0.9.0")
junit-interface 提供對 JUnit4 的支援。請將 junit-interface 依賴項加入到您專案的主要 build.sbt 檔案中。
libraryDependencies += "com.github.sbt" % "junit-interface" % "0.13.3" % Test
此頁面說明如何新增對其他測試程式庫的支援,並定義其他測試報告器。您可以透過實作 sbt
介面(如下所述)來執行此操作。如果您是測試框架的作者,您可以將測試介面作為提供的依賴項。或者,任何人都可以透過在個別專案中實作介面,並將專案打包為 sbt 外掛程式來提供對測試框架的支援。
主要的 Scala 測試程式庫內建支援 sbt。若要新增對不同框架的支援,請實作統一測試介面。
測試框架會將狀態和結果報告給測試報告器。您可以透過實作 TestReportListener 或 TestsListener 來建立新的測試報告器。
若要在專案定義中使用您的擴充功能
修改 testFrameworks
設定以參考您的測試框架
testFrameworks += new TestFramework("custom.framework.ClassName")
透過覆寫您專案定義中的 testListeners
設定,指定您要使用的測試報告器。
testListeners += customTestListener
其中 customTestListener
的類型為 sbt.TestReportListener
。