測試 Crystal 程式碼¶
Crystal 在 Spec
模組中提供功能齊全的規格程式庫。它提供了一個結構,用於編寫程式碼行為方式的可執行範例。
受 Rspec 的啟發,它包含一個領域特定語言 (DSL),可讓您以類似於普通英語的方式編寫範例。
一個基本的規格看起來像這樣
require "spec"
describe Array do
describe "#size" do
it "correctly reports the number of elements in the Array" do
[1, 2, 3].size.should eq 3
end
end
describe "#empty?" do
it "is true when no elements are in the array" do
([] of Int32).empty?.should be_true
end
it "is false if there are elements in the array" do
[1].empty?.should be_false
end
end
end
規格檔案的結構¶
若要使用規格模組和 DSL,您需要在您的規格檔案中加入 require "spec"
。許多專案使用自訂的 規格輔助程式 來組織這些包含項目。
具體的測試案例在 it
區塊中定義。一個可選的(但強烈建議的)描述性字串說明其目的,而一個區塊包含執行測試的主要邏輯。
已經定義或概述但尚未預期可運作的測試案例可以使用 pending
而不是 it
來定義。它們不會被執行,但會在規格報告中顯示為待處理。
it
區塊包含一個範例,該範例應調用要測試的程式碼,並定義對它的期望。每個範例可以包含多個期望,但它應該只測試一個特定的行為。
當包含 spec
時,每個物件都有實例方法 #should
和 #should_not
。這些方法在被測試的值上調用,並以期望作為引數。如果符合期望,程式碼執行會繼續。否則,範例將失敗,並且此區塊中的其他程式碼將不會被執行。
在測試檔案中,規格由範例群組結構化,這些群組由 describe
和 context
區段定義。通常,最上層的 describe
定義規格要測試的外部單元(例如類別)。進一步的 describe
區段可以巢狀在外部單元內,以指定被測試的較小單元(例如個別方法)。
對於單元測試,建議遵循方法名稱的慣例:外部 describe
是類別的名稱,內部 describe
目標是方法。實例方法以 #
為前綴,類別方法以 .
為前綴。
若要建立某些情境 - 想像空陣列與有元素的陣列 - 可以使用 context
方法將其傳達給讀者。它具有不同的名稱,但行為與 describe
完全相同。
describe
和 context
都會採用一個描述作為引數(通常應該是字串)和一個包含個別規格或巢狀分組的區塊。
期望¶
期望定義被測試的值(實際)是否符合特定的值或特定條件。
等價性、同一性和類型¶
有一些方法可以建立期望,這些期望測試等價性 (eq
)、同一性 (be
)、類型 (be_a
) 和 nil (be_nil
)。請注意,同一性期望使用 .same?
,它會測試 #object_id
是否相同。只有當預期的值指向相同的物件而不是等價的物件時,這才是正確的。這僅適用於參考類型,而不適用於結構或數字等值類型。
actual.should eq(expected) # passes if actual == expected
actual.should be(expected) # passes if actual.same?(expected)
actual.should be_a(expected) # passes if actual.is_a?(expected)
actual.should be_nil # passes if actual.nil?
真值¶
actual.should be_true # passes if actual == true
actual.should be_false # passes if actual == false
actual.should be_truthy # passes if actual is truthy (neither nil nor false nor Pointer.null)
actual.should be_falsey # passes if actual is falsey (nil, false or Pointer.null)
比較¶
actual.should be < expected # passes if actual < expected
actual.should be <= expected # passes if actual <= expected
actual.should be > expected # passes if actual > expected
actual.should be >= expected # passes if actual >= expected
其他匹配器¶
actual.should be_close(expected, delta) # passes if actual is within delta of expected:
# (actual - expected).abs <= delta
actual.should contain(expected) # passes if actual.includes?(expected)
actual.should match(expected) # passes if actual =~ expected
預期錯誤¶
這些匹配器會執行一個區塊,並且如果該區塊引發特定的例外,則會通過。
expect_raises(MyError) do
# Passes if this block raises an exception of type MyError.
end
expect_raises(MyError, "error message") do
# Passes if this block raises an exception of type MyError
# and the error message contains "error message".
end
expect_raises(MyError, /error \w{7}/) do
# Passes if this block raises an exception of type MyError
# and the error message matches the regular expression.
end
expect_raises
會傳回已救援的例外,因此可用於進一步的期望,例如驗證例外的特定屬性。
ex = expect_raises(MyError) do
# Passes if this block raises an exception of type MyError.
end
ex.my_error_value.should eq "foo"
聚焦於一組規格¶
describe
、context
和 it
區塊可以用 focus: true
來標記,如下所示
it "adds", focus: true do
(2 + 2).should_not eq(5)
end
如果任何此類項目標記為 focus: true
,則只會執行這些範例。
標記規格¶
標籤可用於分組規格,允許在向規格執行器提供 --tag
引數時僅執行規格的子集(請參閱使用編譯器)。
describe
、context
和 it
區塊可以標記,如下所示
it "is slow", tags: "slow" do
sleep 60
true.should be_true
end
it "is fast", tags: "fast" do
true.should be_true
end
標記一個範例群組 (describe
或 context
) 會延伸到所有包含的範例。
可以透過提供一個 Enumerable
(例如 Array
或 Set
)來指定多個標籤。
執行規格¶
Crystal 編譯器具有一個 spec
命令,其中包含限制要執行的範例和調整輸出的工具。專案的所有規格都透過命令 crystal spec
編譯和執行。
依照慣例,規格位於專案的 spec/
目錄中。規格檔案必須以 _spec.cr
結尾,才能被編譯器命令識別為規格檔案。
您可以從資料夾樹狀結構、個別檔案或檔案中的特定行編譯和執行規格。如果指定的行是 describe
或 context
區段的開頭,則會執行該群組內的所有規格。
預設格式化器會為失敗的規格輸出檔案和行樣式命令,這使得可以輕鬆地重新執行此單獨的規格。
您可以使用切換 --no-color
來關閉色彩。
隨機化規格的順序¶
規格預設會按照定義的順序執行,但是可以透過將 --order random
傳遞給 crystal spec
來以隨機順序執行。
以隨機順序執行的規格會在完成時顯示一個種子值。這個種子值可以用來透過將種子值傳遞給 --order
來以相同的順序重新執行規格。
範例¶
# Run all specs in files matching spec/**/*_spec.cr
crystal spec
# Run all specs in files matching spec/**/*_spec.cr without colors
crystal spec --no-color
# Run all specs in files matching spec/my/test/**/*_spec.cr
crystal spec spec/my/test/
# Run all specs in spec/my/test/file_spec.cr
crystal spec spec/my/test/file_spec.cr
# Run the spec or group defined in line 14 of spec/my/test/file_spec.cr
crystal spec spec/my/test/file_spec.cr:14
# Run all specs tagged with "fast"
crystal spec --tag 'fast'
# Run all specs not tagged with "slow"
crystal spec --tag '~slow'
還有其他選項可以依名稱執行規格、調整輸出格式、執行預執行等,請參閱使用編譯器。
規格輔助程式¶
許多專案使用自訂的規格輔助程式檔案,通常命名為 spec/spec_helper.cr
。
此檔案用於引入 spec
,以及其他所有 spec 檔案都需要的專案程式碼。這裡也是定義全域輔助方法的好地方,這些方法能讓撰寫 spec 更容易,並避免程式碼重複。
require "spec"
require "../src/my_project.cr"
def create_test_object(name)
project = MyProject.new(option: false)
object = project.create_object(name)
object
end
require "./spec_helper"
describe "MyProject::Object" do
it "is created" do
object = create_test_object(name)
object.should_not be_nil
end
end