在 Arturo 軌道上測試

了解如何在 Exercism 上測試你的 Arturo 練習


Arturo 軌道使用 Unitt 3.0.0 單元測試套件來執行所有練習的測試。 這個套件提供了一個測試框架,同時支援現代的 RSpec 風格語法與舊版的 XUnit 風格語法。 在你本機的練習資料夾中執行arturo tester.art或exercism test,第一次執行時會從網際網路安裝這個套件。 或者,你也可以執行arturo --package install unitt 3.0.0來安裝 Unitt。 只有第一個測試會被執行並回報結果給你。 一旦那個測試通過,就取消跳過下一個測試並再次執行測試,直到每個測試都通過為止。 無論是 RSpec 還是 XUnit 的設定,做法都很簡單,只要分別從it.skip或test.skip中移除.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?函式在年份 2015 時應該回傳false。 另一種寫法是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
    ]
]

Unitt v1 中推出的類 XUnit API 是為了向下相容而支援,它與現代的類 RSpec API 大致相同,差別只在於它的斷言較不靈活。

  • suite定義了一組驗證共同事物的測試案例。這些都可以巢狀。
  • test和test.skip都定義了單一測試案例,分別會被執行或跳過。
  • assert帶出測試案例核心的斷言。後面->右側的運算式必須是 true。

使用 XUnit 測試時,通常會在assert那一行之前建立代表結果的變數,以及選擇性的預期值變數。

測試輸出

無論你使用的是 RSpec 還是 XUnit API,測試輸出都會大致相似。 唯一的差別在於每個測試名稱底下印出的內容。 XUnit 會使用求值後的值來回報斷言,所以你會看到false = false。 不過,RSpec 會回報成false? false,因為我們搭配expects使用了false?函式。

從頭說起,如果起始檔案中的panic沒有被移除,Arturo 會回報錯誤,而且不會執行任何測試。

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

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

當你取消跳過更多測試時,這個過程會持續下去。 一旦所有測試都通過,你就完成了這個練習,可以提交解答。 請注意,測試執行器會執行所有測試,無論它們在本機是否被跳過。