Scala 3 — 書籍

使用 sbt 建置和測試 Scala 專案

語言

在這個區段中,您會看到 Scala 專案中常用的兩個工具

我們將先展示如何使用 sbt 建置您的 Scala 專案,然後展示如何將 sbt 和 ScalaTest 結合使用來測試您的 Scala 專案。

如果您想了解有助於將 Scala 2 程式碼移轉到 Scala 3 的工具,請參閱我們的 Scala 3 移轉指南

使用 sbt 建置 Scala 專案

您可以使用多種不同的工具來建置您的 Scala 專案,包括 Ant、Maven、Gradle、Mill 等。但是,名為 sbt 的工具是第一個專門為 Scala 建置的建置工具。

若要安裝 sbt,請參閱 其下載頁面 或我們的 入門 頁面。

建立「Hello, world」專案

您只需幾個步驟即可建立 sbt「Hello, world」專案。首先,建立一個工作目錄,並移至該目錄

$ mkdir hello
$ cd hello

在目錄 hello 中,建立一個子目錄 project

$ mkdir project

在目錄 project 中建立一個名為 build.properties 的檔案,內容如下

sbt.version=1.6.1

然後在專案根目錄中建立一個名為 build.sbt 的檔案,其中包含這行程式碼

scalaVersion := "3.4.1"

現在,建立一個名為類似 Hello.scala 的檔案,名稱的第一部分並不重要,並加入這行

@main def helloWorld = println("Hello, world")

這就夠了。

你的專案結構應如下所示

$ tree
.
├── build.sbt
├── Hello.scala
└── project
    └── build.properties

現在,使用這個 sbt 指令執行專案

$ sbt run

你應該會看到類似這樣的輸出,包括程式中的 "Hello, world"

$ sbt run
[info] welcome to sbt 1.5.4 (AdoptOpenJDK Java 11.x)
[info] loading project definition from project ...
[info] loading settings for project from build.sbt ...
[info] compiling 1 Scala source to target/scala-3.0.0/classes ...
[info] running helloWorld
Hello, world
[success] Total time: 2 s

sbt 啟動器(sbt 命令列工具)會載入 project/build.properties 檔案中設定的 sbt 版本,載入 build.sbt 檔案中設定的 Scala 編譯器版本,編譯 Hello.scala 檔案中的程式碼,並執行產生的位元組碼。

當你檢視目錄時,你會看到 sbt 有個名為 target 的目錄。這些是 sbt 使用的工作目錄。

如你所見,使用 sbt 建立並執行一個小型 Scala 專案只需要幾個簡單的步驟。

在較大的專案中使用 sbt

對於小型專案,這是 sbt 執行所需要的全部。對於需要許多原始碼檔案、相依性或 sbt 外掛程式的大型專案,你會想要建立一個有組織的目錄結構。本節的其餘部分將示範 sbt 使用的結構。

sbt 目錄結構

與 Maven 類似,sbt 使用標準專案目錄結構。這樣的好處是,一旦你熟悉其結構,就可以輕鬆處理其他 Scala/sbt 專案。

首先要知道的是,在專案的根目錄底下,sbt 預期目錄結構如下所示

.
├── build.sbt
├── project/
│   └── build.properties
├── src/
│   ├── main/
│   │   ├── java/
│   │   ├── resources/
│   │   └── scala/
│   └── test/
│       ├── java/
│       ├── resources/
│       └── scala/
└── target/

如果你想要將非受控相依性(JAR 檔案)新增到專案,你也可以在根目錄底下新增一個 lib 目錄。

如果你要建立一個有 Scala 原始碼檔案和測試的專案,但不會使用任何 Java 原始碼檔案,也不需要任何「資源」(例如嵌入式影像、設定檔等),這就你唯一需要在 src 目錄底下新增的內容

.
└── src/
    ├── main/
    │   └── scala/
    └── test/
        └── scala/

使用 sbt 目錄結構的「Hello, world」

建立這個目錄結構很簡單。有工具可以幫你完成這件事,但假設你使用的是 Unix/Linux 系統,你可以使用這些指令建立你的第一個 sbt 專案目錄結構

$ mkdir HelloWorld
$ cd HelloWorld
$ mkdir -p src/{main,test}/scala
$ mkdir project target

執行這些指令後,執行 find . 指令,你應該會看到這個結果

$ find .
.
./project
./src
./src/main
./src/main/scala
./src/test
./src/test/scala
./target

如果你看到這個,表示你已經為下一步做好萬全準備了。

建立 sbt 專案的檔案和目錄還有其他方法。一種方法是使用 sbt new 指令,在 scala-sbt.org 上有說明。這裡沒有說明這種方法,因為它建立的某些檔案比這類入門介紹所需要的還要複雜。

建立第一個 build.sbt 檔案

在這個階段,你只需要再做兩件事才能執行「Hello, world」專案

  • 一個 build.sbt 檔案
  • 一個 Hello.scala 檔案

對於像這樣的迷你專案,build.sbt 檔案只需要一個 scalaVersion 項目,但我們會加入三行你常見的程式碼

name := "HelloWorld"
version := "0.1"
scalaVersion := "3.4.1"

由於 sbt 專案使用標準目錄結構,sbt 可以找到它需要的所有其他檔案。

現在你只需要加入一個小小的「Hello, world」程式。

一個「Hello, world」程式

在大型專案中,你所有的 Scala 原始碼檔案都會放在 src/main/scalasrc/test/scala 目錄下,但對於像這樣的迷你範例專案,你可以將原始碼檔案放在專案的根目錄中。因此,在根目錄建立一個名為 HelloWorld.scala 的檔案,內容如下

@main def helloWorld = println("Hello, world")

這段程式碼定義了一個 Scala 3 的「main」方法,在執行時會印出 "Hello, world"

現在,使用 sbt run 指令編譯並執行你的專案

$ sbt run

[info] welcome to sbt
[info] loading settings for project ...
[info] loading project definition
[info] loading settings for project root from build.sbt ...
[info] Compiling 1 Scala source ...
[info] running helloWorld 
Hello, world
[success] Total time: 4 s

你第一次執行 sbt 時,它會下載它需要的所有內容,執行可能需要幾分鐘,但之後會快很多。

此外,一旦你讓這個第一步順利運作,你會發現互動執行 sbt 快很多。要做到這一點,請先單獨執行 sbt 指令

$ sbt

[info] welcome to sbt
[info] loading settings for project ...
[info] loading project definition ...
[info] loading settings for project root from build.sbt ...
[info] sbt server started at
       local:///${HOME}/.sbt/1.0/server/7d26bae822c36a31071c/sock
sbt:hello-world> _

然後在這個 sbt shell 中,執行它的 run 指令

sbt:hello-world> run

[info] running helloWorld 
Hello, world
[success] Total time: 0 s

這樣就快多了。

如果你在 sbt 命令提示字元中輸入 help,你會看到你可以執行的其他命令清單。但現在,只要輸入 exit(或按 CTRL-D)即可離開 sbt shell。

使用專案範本

手動建立專案結構可能會很繁瑣。謝天謝地,sbt 可以根據範本為你建立專案。

若要從範本建立 Scala 3 專案,請在 shell 中執行下列命令

$ sbt new scala/scala3.g8

Sbt 會載入範本、詢問一些問題,並在子目錄中建立專案檔案

$ tree scala-3-project-template 
scala-3-project-template
├── build.sbt
├── project
│   └── build.properties
├── README.md
└── src
    ├── main
    │   └── scala
    │       └── Main.scala
    └── test
        └── scala
            └── Test1.scala

如果你想建立一個與 Scala 2 交叉編譯的 Scala 3 專案,請使用範本 scala/scala3-cross.g8

$ sbt new scala/scala3-cross.g8

sbt 文件中深入了解 sbt new 和專案範本。

Scala 的其他建置工具

雖然 sbt 被廣泛使用,但還有其他工具可用於建置 Scala 專案

Coursier

順帶一提,Coursier 是一個「相依性解析器」,功能類似於 Maven 和 Ivy。它是用 Scala 從頭開始編寫的,「採用函式程式設計原則」,並平行下載人工製品以快速下載。sbt 使用它來處理大多數相依性解析,並且作為命令列工具,它可用於輕鬆在你的系統上安裝 sbt、Java 和 Scala 等工具,如我們的 入門 頁面所示。

來自 launch 網頁的這個範例顯示 cs launch 命令可用於從相依性啟動應用程式

$ cs launch org.scalameta::scalafmt-cli:2.4.2 -- --help
scalafmt 2.4.2
Usage: scalafmt [options] [<file>...]

  -h, --help               prints this usage text
  -v, --version            print version
  more ...

請參閱 Coursier 的 啟動頁面 了解更多詳細資訊。

將 sbt 與 ScalaTest 搭配使用

ScalaTest 是 Scala 專案的主要測試函式庫之一。在本節中,你將看到建立使用 ScalaTest 的 Scala/sbt 專案所需的步驟。

1) 建立專案目錄結構

與前一課一樣,使用下列命令為名為 HelloScalaTest 的專案建立 sbt 專案目錄結構

$ mkdir HelloScalaTest
$ cd HelloScalaTest
$ mkdir -p src/{main,test}/scala
$ mkdir project

2) 建立 build.properties 和 build.sbt 檔案

接下來,在專案的 project/ 子目錄中建立一個 build.properties 檔案,並加上這行

sbt.version=1.5.4

接下來,在專案的根目錄中建立一個 build.sbt 檔案,並加上以下內容

name := "HelloScalaTest"
version := "0.1"
scalaVersion := "3.4.1"

libraryDependencies ++= Seq(
  "org.scalatest" %% "scalatest" % "3.2.9" % Test
)

此檔案的前三行與第一個範例基本上相同。 libraryDependencies 行告訴 sbt 納入包含 ScalaTest 所需的相依性(JAR 檔案)。

ScalaTest 文件一直都很好,而且您隨時可以在 安裝 ScalaTest 頁面找到這些行應該如何顯示的最新資訊。

3) 建立 Scala 原始碼檔案

接下來,建立一個 Scala 程式,用於展示 ScalaTest。首先,在 src/main/scala 下建立一個名為 math 的目錄

$ mkdir src/main/scala/math
            ----

然後,在該目錄中建立一個名為 MathUtils.scala 的檔案,內容如下

package math

object MathUtils:
  def double(i: Int) = i * 2

該方法提供一個展示 ScalaTest 的簡單方式。

4) 建立您的第一個 ScalaTest 測試

ScalaTest 非常靈活,提供多種撰寫測試的方法。入門的簡單方法是使用 ScalaTest AnyFunSuite 撰寫測試。首先,在 src/test/scala 目錄下建立一個名為 math 的目錄

$ mkdir src/test/scala/math
            ----

接下來,在該目錄中建立一個名為 MathUtilsTests.scala 的檔案,內容如下

package math
  
import org.scalatest.funsuite.AnyFunSuite

class MathUtilsTests extends AnyFunSuite:

  // test 1
  test("'double' should handle 0") {
    val result = MathUtils.double(0)
    assert(result == 0)
  }

  // test 2
  test("'double' should handle 1") {
    val result = MathUtils.double(1)
    assert(result == 2)
  }
 
  test("test with Int.MaxValue") (pending)

end MathUtilsTests

此程式碼展示 ScalaTest AnyFunSuite 方法。幾個重點

  • 您的測試類別應該延伸 AnyFunSuite
  • 您可以透過為每個 test 提供一個唯一名稱來建立測試,如所示
  • 在每個測試的結尾,您應該呼叫 assert 來測試條件是否已滿足
  • 當您知道您想要撰寫測試,但您現在不想撰寫時,請使用所示語法將測試建立為「暫停」

像這樣使用 ScalaTest 類似於 JUnit,因此如果您從 Java 轉到 Scala,希望這看起來很類似。

現在您可以使用 sbt test 指令執行這些測試。略過輸出的前幾行,結果如下所示

sbt:HelloScalaTest> test

[info] Compiling 1 Scala source ...
[info] MathUtilsTests:
[info] - 'double' should handle 0
[info] - 'double' should handle 1
[info] - test with Int.MaxValue (pending)
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 1
[info] All tests passed.
[success] Total time: 1 s

如果一切順利,您會看到類似這樣的輸出。歡迎使用 sbt 和 ScalaTest 測試 Scala 應用程式的世界。

支援多種類型的測試

此範例展示一種測試樣式,類似於 xUnit 測試驅動開發 (TDD) 樣式測試,並具備 行為驅動開發 (BDD) 樣式的幾個優點。

如前所述,ScalaTest 非常靈活,您也可以使用其他樣式撰寫測試,例如類似於 Ruby 的 RSpec 的樣式。您也可以使用模擬物件、基於屬性的測試,以及使用 ScalaTest 來測試 Scala.js 程式碼。

有關不同的測試樣式的更多詳細資訊,請參閱 ScalaTest 網站 上的使用者指南。

下一步

有關 sbt 和 ScalaTest 的更多資訊,請參閱下列資源

此頁面的貢獻者