Тестування на треку Elixir

Дізнаймося, як тестувати вправи з Elixir на Exercism


У терміналі перейдімо до базової теки вправи, а потім виконаймо тести за допомогою:

$ mix test

Це виконає файл тестів із підтеки test, тобто файл, назва якого закінчується на _test.exs.

Відкладені тести

У наборах тестів практичних вправ усі тести, крім першого, позначені як пропущені.

Коли тест почне проходити, ми можемо увімкнути наступний, закоментувавши відповідний @tag :pending символом #.

Наприклад:

# @tag :pending
test "shouting" do
  assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end

Якщо ми хочемо запустити всі тести одразу, можна включити всі пропущені тести за допомогою прапорця --include у команді mix test:

$ mix test --include pending

Або можна увімкнути всі тести, закоментувавши рядок ExUnit.configure у наборі тестів.

# ExUnit.configure exclude: :pending, trace: true

Додаткові можливості тестування в Elixir

ExUnit і mix test пропонують чимало способів групування, тегування й виконання тестів, а також різні способи керування виконанням тестів; більшість із них підсумовано нижче.

Способи запуску конкретних тестів

Документація:

Запуск тестів з окремого файлу

Усі тести з одного файлу можна виконати за допомогою mix test, указавши цей файл:

$ mix test test/<FILE>.exs

ПРИМІТКА: tagging може впливати на те, які тести насправді виконаються в цей спосіб.

Запуск окремих тестів

Окремі тести можна виконати, указавши номер рядка тесту у файлі:

$ mix test test/<FILE>.exs:LINENUM

Кілька тестів можна виконати, указавши кілька номерів рядків, розділених :.

Наприклад, для файлу з таким вмістом і номерами рядків:

test "Test 1" do           # 1
  # test implementation    # 2-6
end                        # 7
                           # 8
test "Test 2" do           # 9
  # test implementation    # 10-21
end                        # 22
                           # 23
test "Test 3" do           # 24
  # test implementation    # 25-35
end                        # 36

Перший і третій тести можна виконати так:

$ mix test test/FILE.exs:1:24

ПРИМІТКА: коли тести вказують через номери рядків, tagging ігнорується.

Запуск груп тестів

Тести можна групувати за допомогою describe:

describe "short test group description" do
  test "test description" do
    # test implementation
  end

  test "another test description" do
    # test implementation
  end
end

Усі тести з групи можна виконати, указавши номер її рядка у файлі, так само, як ми вказуємо та виконуємо окремі тести.

Документація:

Інші корисні параметри mix test

  • --include і --exclude - запускають або не запускають конкретні тести залежно від їхніх @tag
  • --failed - запускає лише ті тести, які не пройшли минулого разу
  • --max-failures - набір тестів перестає виконувати тести, коли досягнуто цієї кількості невдач
  • --seed - задає початкове значення генератора випадкових чисел, який перемішує порядок тестів. --seed 0 вимикає перемішування, тож тести в одному файлі завжди виконуватимуться в тому порядку, у якому їх визначено
  • --stale - запускає лише ті тести, які посилаються на модулі, що змінилися відтоді, як тести востаннє запускали з --stale
  • --only task_id:1 - або з іншим номером: у навчальних вправах запускає лише тести, повʼязані з конкретним завданням

Документація:

Типоспецифікації та Dialyzer (DIscrepancy AnalYZer for ERlang programs)

Вправи з Elixir містять файл-заготовку з реалізацією в підтеці lib. Цей файл окреслює модуль і функції, які нам належить реалізувати. У більшості вправ ми знайдемо типоспецифікації над оголошенням функції. Вони починаються з тегу @spec і зазвичай мають формат @spec function_name(type1, type2) :: return_type. Їх використовують в Elixir та Erlang як документацію і разом з інструментом Dialyzer, щоб знаходити невідповідності типів і можливі помилки. Докладніше див. документацію про типоспецифікації. Про Dialyzer див. Erlang -- dialyzer.

За бажанням можна перевірити типи своєї реалізації за допомогою Dialyzer. Для цього потрібно зробити кілька кроків. Щоб це зробити, треба додати залежність Dialyxir у файл mix.exs своєї вправи.

defp deps do
  # Add this:
  [{:dialyxir, "~> 0.4", only: [:dev]}]
end

Потім скористаймося завданнями mix, щоб завантажити й скомпілювати їх із командного рядка:

$ mix deps.get
...
$ mix deps.compile
...

Якщо ми запускаємо Dialyzer уперше, файлу plt, найімовірніше, ще не буде. Постійна таблиця пошуку, або PLT, використовується Dialyzer для кешування інформації про вбудовані типи Elixir та Erlang. Щоб створити plt із прийнятними типовими значеннями, виконаймо:

$ mix dialyzer --plt

Нарешті, його можна запустити так:

$ mix dialyzer

Обовʼязково замінімо шлях на шлях до бібліотек Elixir у нашій системі. Наприклад, якщо ми встановили Elixir через homebrew, то, найімовірніше, знайдемо його за шляхом /usr/local/Cellar/elixir/1.3.2.

Повторимо ще раз: запуск Dialyzer і виправлення всіх попереджень - необовʼязковий крок під час виконання вправи. Попередження Dialyzer буває важко розшифрувати. Наприклад, погляньмо на попередження для цієї вкрай безглуздої реалізації вправи Bob.

defmodule Bob do
  @spec hey(input :: String.t()) :: String.t()
  def hey(input) do
    1
  end

  def hey(input) do
  end
end

Це дає такі попередження.

bob.exs:2: Invalid type specification for function 'Elixir.Bob':hey/1. The success typing is (_) -> 1
bob.exs:7: The variable _input@1 can never match since previous clauses completely covered the type any()

Перше попередження означає, що функція повертає не той тип. Останнє вказує на те, що до другого визначення функції ніколи не дійде черга, бо перше визначення функції завжди збігається.