Unit-тестирование#

При необходимости проверки работоспособности отдельных частей исходного кода имеется возможность реализации unit-тестирования на основе ScalaTest.

Для создания набора тестов создайте класс, который будет наследоваться от LangFunSuite, ApiTest или других классов, в которые подмешаны трейты из ScalaTest.

Совет

Для дополнительной информации смотрите библиотеку unit тестирования: scalatest.

Создание класса с тестами#

  1. Перейдите в окно проекта.

  2. Выберете целевой модуль.

  3. Перейдите в папку с исходными кодами:
    [module_name]/src/test/scala

    Совет

    Создать недостающую папку можно из контекстного меню в idea New > Directory.

  4. Создайте пакет ru.bitec.app.[module_name].

  5. Создайте тестовый класс:

     class Lesson1Test extends LangFunSuite{
       test("HelloWorld"){
           println("hello world")
       }
     }
    

Совет

Запустите тест из контекстного меню, для этого:

  1. Переведите курсор на декларацию функции или класса, если нужно запустить все объявленные тесты класса.

  2. В контекстном меню выполните операцию „Debug“ для запуска в режиме отладки или „Run“ для простого запуска.

Подробнее смотрите выполнение тестов в руководстве idea.

Примечание

Существуют два специализированных базовых класса для тестовых случаев:

  • LangFunSuite - используется для тестов, которые не нуждаются в контроллерах бизнес логики.

    Данные тесты не могут использовать Api, Pkg и не имеют подключения к базе данных по умолчанию.

  • ApiTest - в данном тексте доступен контекст автономной бизнес логики. Тестовые случаи могут использовать Api,Pkg объекты. При этом запуск теста становится медленней из за необходимости инициализировать контекст.

Базовые Assert методы#

Трейт Assertions содержит основные методы для проверки предположений.

  1. Assert(condition: Boolean).

Этот метод проверяет условие. Если переданное условие возвращает true, то метод завершается нормально, иначе выбрасывает ошибку TestFailedException.

Пример:

  test("создание объекта класса Btk_SomeClass") {
    try {
      val rop = Btk_SomeClassApi().insert()
      assert(Btk_SomeClassExtApi().findSomeClassExt(rop).isDefined)
    } finally {
      session.rollback()
    }
  }

Данный тест проверяет, что при создании объекта Btk_SomeClass для него создаётся расширение Btk_SomeClassExt. Если расширение не было создано, то тест не будет пройден.
В консоль будет выведен текст ошибки :

Btk_SomeClassExtApi.apply().findSomeClassExt(rop).isDefined was false

В assert можно передать дополнительный комментарий, который будет добавляться к тексту ошибки:

  test("создание объекта класса Btk_SomeClass") {
    try {
      val rop = Btk_SomeClassApi().insert()
      assert(rop.get(_.dBeginDate).isNotNull, "При создании не установилась дата начала.")
      assert(Btk_SomeClassExtApi().findSomeClassExt(rop).isDefined, "При создании не зарегистрировалось расширение.")
    } finally {
      session.rollback()
    }
  }
  1. assertResult(expected: Any)(actual: Any).

Сравнивает ожидаемое ожидаемое значение с переданным:

  test("parseGtkSessionClientFullName") {
    val x = WorkSessionClientHelper.parseGtkSessionClientFullName("DESkTOP-23565:8080#E1@123-45")
    assert(x.isDefined)
    assertResult("DESkTOP-23565:8080")(x.get._1)
    assertResult("E1")(x.get._2)
    assertResult("123-45")(x.get._3)
  }
  1. assertThrows[T <: AnyRef](f: => Any).

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

  test("data.oaObjQty.isEmpty") {
    val data = new Bs_DistrData()
    assertThrows[AppException] {
      Bs_DistributionPkg().distribQty(data)
    }
  }
  1. assume(condition: Boolean).

Метод aналогичен методу assert, но в случае, когда не выполняется условие, не завершается ошибкой, а отменяет тест. Так же может содержать пояснительный комментарий:

assume(database.isAvailable, "База данных не доступна.")
assume(database.getAllUsers.count === 9)
  1. intercept[T <: AnyRef](f: => Any).

Метод aналогичен методу assertThrows, но позволяет получить ошибку ожидаемого типа для более детальной проверки:

        val vEx = intercept[AppException] {
          _api.validateOnBeforeManualInsert(ropDuplicate)
        }
        assert(vEx.getMessage.startsWith("Ошибка. Уже существует запись с классом типа объектов:"))

Matchers#

Трейт Matchers позволяет использовать в тестах комбинаторы вроде shouldBe вместо обычного assert, улучшая читаемость кода.

По умолчанию к ApiTest и LangFunSuite Matchers не подключен, поэтому чтобы использовать его методы, добавьте его в объявлении класса:

class Bs_AccApiTest extends ApiTest with Matchers {
  test("set level on insert") {
    val rop = api.insert()
    rop.get(_.nLevel) should ===(1.nn)
  }
}

Для дополнительной информации смотрите в руководстве пользователя: matchers.

Некоторые примеры:

  1. Проверка размера и длины.

Для проверки размера и длины используйте:

  • <проверяемый объект> should have length (<ожидаемое значение>);

  • <проверяемый объект> should have size (<ожидаемое значение>).

Пример:

  test("проверка размера массива") {
    val result = getArgs()
    result should have length (3)
  }
  1. Проверка строк:

  • на наличие подстроки:

    string should startWith ("Hello")
    string should endWith ("world")
    string should include ("seven")
  • с использованием регулярных выражений:

    string should startWith regex ("Hel*o")
    string should endWith regex ("wo.ld")
    string should include regex ("wo.ld")
  • проверка всей строки на соответствие регулярному выражению:

    string should fullyMatch regex ("""(-)?(\d+)(\.\d*)?""")
  1. Сравнения больше/меньше/равно:
    Можно сравнивать объекты любого типа, кроме тех, которые могут быть преобразованы в Ordered[T]. Для сравнения списков, используйте greater than, less than, greater than or equal, less than or equal to a value of type T

    one should be < (7)
    one should be > (0)
    one should be <= (7)
    one should be >= (0)
  • с использованием регулярных выражений:

    string should startWith regex ("Hel*o")
    string should endWith regex ("wo.ld")
    string should include regex ("wo.ld")
  • проверка всей строки на соответствие регулярному выражению:

    string should fullyMatch regex ("""(-)?(\d+)(\.\d*)?""")