Сборка и тестирование проектов Scala с помощью Sbt
В этом разделе будут показаны два инструмента, которые обычно используются в проектах Scala:
Начнем с использования sbt для создания Scala-проектов, а затем рассмотрим, как использовать sbt и ScalaTest вместе для тестирования.
Создание проектов Scala с помощью sbt
Можно использовать несколько различных инструментов для создания проектов Scala, включая Ant, Maven, Gradle, Mill и другие. Но инструмент под названием sbt был первым инструментом сборки, специально созданным для Scala.
Чтобы установить sbt, см. страницу загрузки.
Создание проекта "Hello, world"
Вы можете создать sbt проект "Hello, world" всего за несколько шагов. Сначала создайте каталог для работы и перейдите в него:
$ mkdir hello
$ cd hello
В каталоге hello создайте подкаталог project
:
$ mkdir project
Создайте файл с именем build.properties в каталоге project
со следующим содержимым:
sbt.version=1.6.2
Затем создайте файл с именем build.sbt в корневом каталоге проекта (hello
), содержащий следующую строку:
scalaVersion := "3.1.3"
Теперь создайте файл с именем 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.6.1 (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.1.3/classes ...
[info] running helloWorld
Hello, world
[success] Total time: 2 s
Программа запуска — средство командной строки sbt
- загружает версию sbt,
установленную в файле project/build.properties, которая загружает версию компилятора Scala,
установленную в файле build.sbt, компилирует код в файле Hello.scala и запускает результирующий байт-код.
Если посмотреть на корневой каталог, то можно увидеть, что появилась папка с именем target. Это рабочие каталоги, которые использует 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/
Также в корневой каталог можно добавить каталог lib, если необходимо в свой проект добавить неуправляемые зависимости — файлы JAR.
Если достаточно создать проект, который имеет только файлы исходного кода Scala и тесты,
но не будет использовать Java файлы
и не нуждается в каких-либо "ресурсах" (встроенные изображения, файлы конфигурации и т.д.),
то в каталоге src
можно оставить только:
.
└── src/
├── main/
│ └── scala/
└── test/
└── scala/
"Hello, world" со структурой каталогов sbt
Создать такую структуру каталогов просто. Существуют инструменты, которые сделают это за вас, но если вы используете систему 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.1.3"
Поскольку проекты sbt используют стандартную структуру каталогов, sbt может найти все, что ему нужно.
Теперь осталось просто добавить небольшую программу "Hello, world".
Программа "Hello, world"
В больших проектах все файлы исходного кода будут находиться в каталогах src/main/scala и src/test/scala, но для небольшого примера, подобного этому, можно поместить файл исходного кода в корневой каталог. Поэтому создайте файл с именем HelloWorld.scala в корневом каталоге со следующим содержимым:
@main def helloWorld = println("Hello, world")
Этот код определяет "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> _
Затем внутри этой оболочки выполните команду run
:
sbt:hello-world> run
[info] running helloWorld
Hello, world
[success] Total time: 0 s
Так намного быстрее.
Если вы наберете help
в командной строке sbt, то увидите список других команд, доступных для запуска.
Введите exit
(или нажмите CTRL-D
), чтобы выйти из оболочки sbt.
Использование шаблонов проектов
Ручное создание структуры проекта может быть утомительным. К счастью, sbt может создать структуру на основе шаблона.
Чтобы создать проект Scala 3 из шаблона, выполните следующую команду в оболочке:
$ 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 3, который кросс-компилируется со Scala 2, используйте шаблон
scala/scala3-cross.g8
:$ sbt new scala/scala3-cross.g8
Узнайте больше о sbt new
и шаблонах проектов в
документации sbt.
Другие инструменты сборки для Scala
Хотя sbt широко используется, есть и другие инструменты, которые можно использовать для создания проектов Scala:
Coursier
Coursier - это "преобразователь зависимостей", похожий по функциям на Maven и Ivy. Он написан на Scala с нуля, "охватывает принципы функционального программирования" и для быстроты параллельно загружает артефакты. sbt использует Coursier для обработки большинства разрешений зависимостей, а в качестве инструмента командной строки его можно использовать для простой установки таких инструментов, как sbt, Java и Scala, как показано на странице "С чего начать?".
Этот пример показывает, что команда 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. В этом разделе рассмотрим шаги, необходимые для создания проекта Scala/sbt, использующего ScalaTest.
1) Создание структуры каталогов проекта
Как и в предыдущем уроке, создаем структуру каталогов sbt для проекта с именем HelloScalaTest с помощью следующих команд:
$ mkdir HelloScalaTest
$ cd HelloScalaTest
$ mkdir -p src/{main,test}/scala
$ mkdir project
2) Создание файлов build.properties и build.sbt
Затем создаем файл build.properties в подкаталоге project/ проекта с такой строкой:
sbt.version=1.6.2
Создаем файл build.sbt
в корневом каталоге проекта со следующим содержимым:
name := "HelloScalaTest"
version := "0.1"
scalaVersion := "3.1.3"
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.2.9" % Test
)
Первые три строки этого файла практически такие же, как и в первом примере.
Строки libraryDependencies
сообщают sbt о включении зависимостей (файлов JAR),
которые необходимы для добавления ScalaTest.
Документация по 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 очень гибок и предлагает несколько различных способов написания тестов.
Простой способ начать работу — написать тесты с помощью AnyFunSuite
.
Для начала создайте каталог с именем math в каталоге src/test/scala:
$ 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
Этот код демонстрирует AnyFunSuite
подход.
Несколько важных моментов:
- тестовый класс должен расширять
AnyFunSuite
- тесты создаются, задавая каждому
test
уникальное имя - в конце каждого теста необходимо вызвать
assert
, чтобы проверить, выполнено ли условие - когда вы знаете, что хотите написать тест, но не хотите писать его прямо сейчас, создайте тест как "pending" (ожидающий) с показанным синтаксисом
Подобное использование ScalaTest похоже на JUnit.
Теперь можно запустить эти тесты с помощью команды 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
Поддержка различных видов тестов
В этом примере демонстрируется стиль тестирования, аналогичный стилю xUnit Test-Driven Development (TDD), с некоторыми преимуществами Behavior-Driven Development (BDD).
Как уже упоминалось, ScalaTest является гибким, и вы также можете писать тесты, используя другие стили, такие как стиль, похожий на RSpec Ruby. Вы также можете использовать моканные объекты, тестирование на основе свойств и использовать ScalaTest для тестирования кода Scala.js.
Дополнительные сведения о различных доступных стилях тестирования см. в Руководстве пользователя на веб-сайте ScalaTest.
Что дальше?
Дополнительные сведения о sbt и ScalaTest см. в следующих ресурсах:
Ссылки: