Я занимался программированием, написав библиотеку, которая в основном выполняет механизмы повторных попыток, основанные на замечательной библиотеке zmanio / atmos, которая, к сожалению, больше не поддерживается и не публикуется для scala 2.12.

Я начал писать тесты после того, как написал несколько базовых трейтов и реализаций, и на этот раз я поставил перед собой задачу написать тесты настолько хорошо, насколько это возможно.

Это то, что я узнал из процесса, давайте начнем.

Тестовые кейсы

Согласно документации ScalaTest, вы можете использоватьTableDrivenPropertyCheck только с PropSpec, но есть другой способ легко создавать «Тестовые наборы» практически с любым другим стилем тестирования:

И результаты прогона:

[info] CalculatorSpec:
[info] add
[info] - should return 2 for 1 and 1
[info] add
[info] - should return 4294967294 for 2147483647 and 2147483647

Как видите, слово «добавить» появляется в журнале дважды. Я действительно пытался что-то с этим сделать, но лучшим вариантом, который я нашел, было изменить стиль спецификации на FunSuite:

Теперь журнал выглядит лучше:

[info] CalculatorSpec:
[info] - add should return 2 for 1 and 1
[info] - add should return 4294967294 for 2147483647 and 2147483647

TypeCheckedTripleEquals

ScalaTest поддерживает известный оператор ===. Для тех из вас, кто не изучал JavaScript, этот оператор утверждает равенство значения и типа. Это действительно полезно, когда вы меняете тип возвращаемого значения метода и утверждаете результат метода - в этом случае компиляция завершится ошибкой.

Использовать это просто, просто добавьте (или импортируйте) признак org.scalactic.TypeCheckedTripleEquals и используйте его:

Этот код выше не будет компилироваться:

[error] .../Examples.scala:8: types Long and Int do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Long,Int]
[error]     target should === (5)

Чтобы он скомпилировался, вам нужно изменить строку 8 на:

target should === (5L)

Абстрактная базовая спецификация

Вы можете создать abstract спецификации для повторного использования одного и того же кода в тестах, проверяющих одну и ту же черту. Вы можете подумать, что это вариант использования поведенческих тестов. Но наши реализации не ведут себя одинаково, поэтому нам нужны разные случаи для каждой реализации. Я продемонстрирую один способ сделать это.

Предположим, у нас есть трейт, который вычисляет задержку на основе количества неудачных попыток:

trait Backoff {
  def calculate(attempts: Int): FiniteDuration
}

У нас может быть много реализаций этой черты: NoBackoff, ConstantBackoff, LinearBackoff, ExponentialBackoff, FibonacciBackoff, RandomBackoff и многие другие.

Мы можем упасть, чтобы повториться при написании тестов. Вместо этого давайте реализуем BackoffSpec, который является абстрактным и унаследован от него для каждой реализации:

Как видите, я использовал первый совет для создания множества тестовых примеров для каждого Spec, просмотрите журнал, созданный в результате выполнения этих тестов:

[info] ConstantBackoffSpec:
[info] - calculate should return 1 second for 1 attempts
[info] - calculate should return 1 second for 2 attempts
[info] NoBackoffSpec:
[info] - calculate should return 0 days for 1 attempts
[info] - calculate should return 0 days for 2 attempts

Приятно и самое приятное - ScalaTest не запускает абстрактную спецификацию, поскольку она абстрактная!

Пользовательские сопоставители

ScalaTest позволяет нам писать настраиваемые сопоставители для определенных типов и делать тест более читаемым, особенно при тестировании объектов предметной области.

Эта функция очень хорошо документирована. И их пример великолепен:

file should endWithExtension ("txt")

намного читабельнее, чем:

file.getName should endWith (".txt")

Дополнительный совет: непрерывное тестирование с SBT

Мой любимый способ работы с тестами - разделить экран на два: одна часть для IntelliJ IDEA (или вашей любимой IDE), а другая часть для терминала, на котором запущен SBT со специальной запущенной в нем командой.

При запуске ~test-quick мы получаем лучшее из всех возможных: SBT будет следить за изменениями в нашем исходном коде, а ScalaTest будет запускать только те тесты, на которые повлияли внесенные изменения.

Выполнение тестов с использованием этого метода позволяет вам писать код без прерывания рабочего процесса и быть уверенным в том, что вы ничего не сломали.

Обобщить

Написание автоматических тестов - это часть нашей работы как разработчиков программного обеспечения, и они не должны рассматриваться как люди второго сорта в нашей кодовой базе.

Как только вы начнете рассматривать свой тестовый код так же, как код «времени выполнения», его код будет намного сложнее и интереснее.

Наслаждайтесь тестированием и, пожалуйста, ответьте, если у вас есть другие способы сделать «Тестирование снова отличным!»