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

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


Трек Arturo використовує пакет модульного тестування Unitt 3.0.0 для всіх тестів у вправах. Цей пакет надає фреймворк для тестування, який підтримує як сучасний синтаксис у стилі RSpec, так і застарілий синтаксис у стилі XUnit. Запуск arturo tester.art або exercism test у локальній теці вправи під час першого запуску має встановити цей пакет з інтернету. Крім того, Unitt можна встановити, виконавши arturo --package install unitt 3.0.0. Запуститься лише перший тест, і його результат буде повідомлено. Коли цей тест пройде, зніміть пропуск із наступного тесту й запускайте тести знову, доки кожен із них не пройде. І для RSpec, і для XUnit це так само просто, як прибрати .skip з it.skip або test.skip відповідно. Коли всі тести пройдуть, надішліть своє рішення, але майте на увазі, що засіб запуску тестів виконує всі тести, навіть пропущені.

Початок роботи

У завантаженій теці вправи буде кілька файлів, але ось три найважливіші з них.

leap/
├── src/leap.art         # Your solution file
├── tests/test-leap.art  # Test cases for the exercise
└── tester.art           # Test runner entry point

Запуск arturo tester.art налаштує Unitt, а потім запустить тести з tests/test-leap.art. Тести імпортують src/leap.art, який містить ваше рішення, а потім роблять низку тверджень про те, що ваше рішення має повертати для конкретних вхідних даних.

Файл рішення

isLeap?: function [year][
    panic "please implement the isLeap? function"
]

На початку вправи файл рішення містить шаблон із базовою структурою того, що очікується. У цьому прикладі з Leap файл містить мінімальне визначення очікуваної функції isLeap? і, що важливо, panic, який зупиняє виконання тестів. Приберіть рядок із panic і починайте писати свою реалізацію isLeap?.

Структура тестів RSpec

import.version:3.0.0 {unitt}!
import {src/leap}!

describe "Leap" [
    it "a year not divisible by 4 is a common year" [
        expects.be:'false? @[isLeap? 2015]
    ]

    it.skip "a year divisible by 4 and not divisible by 100 is a leap year" [
        expects.be:'true? @[isLeap? 1996]
    ]
]
  • describe визначає блок тестових випадків, які перевіряють щось спільне. Такі блоки можна вкладати один в одного.
  • it та it.skip визначають один тестовий випадок, який відповідно або запускається, або пропускається.
  • expects вводить твердження, яке лежить в основі тестового випадку. expects.be приймає функцію-предикат, за допомогою якої робиться твердження.

У expects.be:'false? @[isLeap? 2015] набір тестів стверджує, що функція isLeap? має повернути false для 2015 року. Інакше це можна записати як expects.be:'equal? @[false isLeapYear? 2015], де ми стверджуємо, що повернене значення isLeapYear? 2015 дорівнює false. Ця довша форма з порівнянням двох значень є найпоширенішим типом твердження на треку Arturo. Очікуване значення завжди стоїть першим у блоці, перед значенням результату.

Структура тестів XUnit

suite "Leap" [
    test "a year not divisible by 4 is a common year" [
        result: isLeap? 2015
        assert -> false = result
    ]

    test.skip "a year divisible by 4 and not divisible by 100 is a leap year" [
        result: isLeap? 1996
        assert -> true = result
    ]
]

API у стилі XUnit, представлений у версії 1 Unitt, підтримується для зворотної сумісності й загалом рівнозначний сучасному API у стилі RSpec, окрім менш гнучких тверджень.

  • suite визначає блок тестових випадків, які перевіряють щось спільне. Такі блоки можна вкладати один в одного.
  • test та test.skip визначають один тестовий випадок, який відповідно або запускається, або пропускається.
  • assert вводить твердження, яке лежить в основі тестового випадку. Вираз праворуч від -> має бути правдивим.

У тестах XUnit зазвичай перед рядком assert створюють змінні для результату й, за потреби, для очікуваного значення.

Вивід тестів

Незалежно від того, чи ми використовуємо API RSpec чи XUnit, вивід тестів буде приблизно однаковим. Різниця буде лише в тому, що друкується під назвою кожного тесту. XUnit повідомляє про твердження, використовуючи обчислені значення, тож ми побачимо false = false. RSpec же повідомляє його як false? false, бо ми використали функцію false? разом з expects.

Почнімо спочатку: Arturo повідомить про помилку, якщо panic з початкового файлу не прибрано, і не виконуватиме жодного тесту.

Uncaught error in tests/test-leap.art:
#[
        output: {
                
                ══╡ Program Error ╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ <script> ══
                
                  Please implement the isLeap? function
                
                
        }
        code: 1
]

Щойно panic буде замінено, Arturo повідомить статус кожного твердження, зробленого в межах тесту. Тепер перший тест проходить, а другий пропущено.

======== .unitt/tests/test-leap.art ========

Describe: Leap

    ✅ - assert that a year not divisible by 4 is a common year
         ✅: false? false

    ⏩ - assert that a year divisible by 4 and not divisible by 100 is a leap year
         skipped!


========== Summary ==========

⏏️   TOTAL: 2 assertions
✅  PASSED: 1 assertion
⏩ SKIPPED: 1 assertion
❌  FAILED: 0 assertion

========== ======= ==========

Після того як ми вручну знімемо пропуск із другого тесту, запустяться обидва тести. Однак поточна реалізація коду isLeap? повертає лише false, тож другий тест провалює своє твердження.

======== .unitt/tests/test-leap.art ========

Describe: Leap

    ✅ - assert that a year not divisible by 4 is a common year
         ✅: false? false

    ❌ - assert that a year divisible by 4 and not divisible by 100 is a leap year
         ❌: true? false


========== Summary ==========

⏏️   TOTAL: 2 assertions
✅  PASSED: 1 assertion
⏩ SKIPPED: 0 assertion
❌  FAILED: 1 assertion

========== ======= ==========

Цей процес триватиме, поки ми знімаємо пропуски з наступних тестів. Коли всі тести пройдуть, вправу завершено й рішення можна надіслати. Зауважте, що засіб запуску тестів локально виконує всі тести, незалежно від того, чи мають вони позначку пропуску.