Crystalコードのテスト¶
Crystalには、Spec
モジュールにフル機能のspecライブラリが付属しています。これは、コードの動作方法の実行可能な例を作成するための構造を提供します。
Rspecにインスパイアされたこのライブラリには、ドメイン固有言語(DSL)が含まれており、平易な英語と同様の方法で例を作成できます。
基本的なspecは次のようになります。
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
specファイルの構成¶
specモジュールとDSLを使用するには、specファイルにrequire "spec"
を追加する必要があります。多くのプロジェクトでは、これらのインクルードを整理するカスタムspecヘルパーを使用しています。
具体的なテストケースは、it
ブロックで定義されます。オプションの(ただし強く推奨される)説明的な文字列はその目的を示し、ブロックにはテストを実行するメインロジックが含まれます。
定義または概説されているが、まだ動作することが期待されていないテストケースは、it
の代わりにpending
を使用して定義できます。これらは実行されませんが、保留中のものとしてspecレポートに表示されます。
it
ブロックには、テスト対象のコードを呼び出し、そのコードから期待される動作を定義する例が含まれています。各例には複数の期待値を含めることができますが、1つの特定の動作のみをテストする必要があります。
spec
が含まれている場合、すべてのオブジェクトにインスタンスメソッド#should
と#should_not
があります。これらのメソッドは、引数として期待値を使用して、テスト対象の値で呼び出されます。期待値が満たされると、コードの実行は継続します。そうでない場合、例は失敗し、このブロック内の他のコードは実行されません。
テストファイルでは、specは、describe
セクションとcontext
セクションで定義された例グループによって構造化されます。通常、最上位のdescribe
は、specによってテストされる外部ユニット(クラスなど)を定義します。さらに、describe
セクションは外部ユニット内にネストして、テスト対象のより小さなユニット(個々のメソッドなど)を指定できます。
ユニットテストでは、メソッド名の規則に従うことをお勧めします。外部のdescribe
はクラスの名前、内部のdescribe
はメソッドを対象とします。インスタンスメソッドには#
、クラスメソッドには.
が接頭辞として付けられます。
特定のコンテキスト(「空の配列」対「要素を含む配列」など)を確立するために、context
メソッドを使用してこれを閲覧者に伝えることができます。名前は異なりますが、describe
とまったく同じように動作します。
describe
とcontext
は、引数として説明(通常は文字列)と、個々のspecまたはネストされたグループを含むブロックを取ります。
期待値¶
期待値は、テスト対象の値(実際値)が特定の値または特定の条件と一致するかどうかを定義します。
等価性、同一性、型¶
等価性(eq
)、同一性(be
)、型(be_a
)、およびnil(be_nil
)をテストする期待値を作成するメソッドがあります。同一性の期待値は#object_id
が同一かどうかをテストする.same?
を使用することに注意してください。これは、期待値が同じオブジェクトではなく同等のオブジェクトを指している場合にのみ当てはまります。これは参照型の場合にのみ可能であり、構造体や数値などの値型では機能しません。
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"
specグループへのフォーカス¶
describe
、context
、it
ブロックには、次のようにfocus: true
を付けることができます。
it "adds", focus: true do
(2 + 2).should_not eq(5)
end
このようなものがfocus: true
でマークされている場合、それらの例のみが実行されます。
specへのタグ付け¶
タグを使用してspecをグループ化し、specランナーに--tag
引数を指定してspecのサブセットのみを実行できます(コンパイラの使用を参照)。
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
など)を指定することで、複数のタグを指定できます。
specの実行¶
Crystalコンパイラには、実行される例を制限し、出力を調整するためのツールを備えたspec
コマンドがあります。プロジェクトのすべてのspecは、crystal spec
コマンドによってコンパイルおよび実行されます。
慣例により、specはプロジェクトのspec/
ディレクトリに配置されます。specファイルは、コンパイラコマンドによって認識されるように、_spec.cr
で終わる必要があります。
フォルダツリー、個々のファイル、またはファイル内の特定の行からスペックをコンパイルして実行できます。指定された行が`describe`または`context`セクションの先頭にある場合、そのグループ内のすべてのスペックが実行されます。
デフォルトのフォーマッタは、失敗したスペックのファイルと行のスタイルのコマンドを出力します。これにより、その個々のスペックだけを簡単に再実行できます。
--no-color
スイッチを使用して、カラー表示をオフにすることができます。
スペックの実行順序のランダム化¶
スペックはデフォルトでは定義されている順序で実行されますが、`crystal spec`に`--order random`を渡すことで、ランダムな順序で実行できます。
ランダムな順序で実行されたスペックは、完了時にシード値を表示します。このシード値を使用して、`--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`と、すべてのスペックファイルに必要なプロジェクトからのコードなどの他のインクルードを必要とするために使用されます。これは、スペックの作成を容易にし、コードの重複を避けるグローバルヘルパーメソッドを定義するのに適した場所でもあります。
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