http://betterspecs.org/#subjectには、とに関する情報がsubject
ありlet
ます。しかし、私はそれらの違いについてはまだはっきりしていません。さらに、SOの投稿RSpecテストでbefore、let、subjectを使用することに反対する議論は何ですか?subject
またはを使用しない方が良いと述べましたlet
。どこに行こうか?私はとても混乱しています。
http://betterspecs.org/#subjectには、とに関する情報がsubject
ありlet
ます。しかし、私はそれらの違いについてはまだはっきりしていません。さらに、SOの投稿RSpecテストでbefore、let、subjectを使用することに反対する議論は何ですか?subject
またはを使用しない方が良いと述べましたlet
。どこに行こうか?私はとても混乱しています。
回答:
概要:RSpecのサブジェクトは、テストされるオブジェクトを参照する特別な変数です。期待値は暗黙的に設定でき、1行の例をサポートします。一部の慣用的なケースでは読者には明らかですが、それ以外の場合は理解が難しく、避ける必要があります。RSpecのlet
変数は、怠惰にインスタンス化された(メモ化された)変数です。それらは主題ほど従うのは難しいことではありませんが、それでももつれたテストにつながる可能性があるので、慎重に使用する必要があります。
サブジェクトはテスト対象のオブジェクトです。RSpecは主題について明確な考えを持っています。定義されている場合とされていない場合があります。そうである場合、RSpecは明示的に参照せずにメソッドを呼び出すことができます。
デフォルトでは、最も外側のサンプルグループ(describe
またはcontext
ブロック)の最初の引数がクラスである場合、RSpecはそのクラスのインスタンスを作成し、それをサブジェクトに割り当てます。たとえば、次のパスがあります。
class A
end
describe A do
it "is instantiated by RSpec" do
expect(subject).to be_an(A)
end
end
あなたはあなた自身で主題を定義することができますsubject
:
describe "anonymous subject" do
subject { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
サブジェクトを定義するときに、サブジェクトに名前を付けることができます。
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(a).to be_an(A)
end
end
件名に名前を付けても、匿名で参照できます。
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
複数の名前付きサブジェクトを定義できます。最近定義された名前付きサブジェクトはanonymoussubject
です。
ただし、主題は定義されていますが、
怠惰にインスタンス化されます。つまり、記述されたクラスの暗黙的なインスタンス化または渡されたブロックの実行は、例で指定されたサブジェクトが参照されるsubject
まで発生しませんsubject
。(グループ内の例が実行される前に)明示的なサブジェクトを熱心にインスタンス化する場合は、のsubject!
代わりに言いますsubject
。
期待値は暗黙的に設定できます(書き込みsubject
や名前付きサブジェクトの名前なしで):
describe A do
it { is_expected.to be_an(A) }
end
サブジェクトは、この1行の構文をサポートするために存在します。
暗黙的subject
(サンプルグループから推測)は、次の理由で理解するのが困難です。
is_expected
明示的なレシーバーなしで呼び出すことによって)使用されるか、明示的に(asとしてsubject
)使用されるかにかかわらず、期待値が呼び出されているオブジェクトの役割または性質に関する情報を読者に提供しません。it
通常の例の構文ではの文字列引数)がないため、例の目的について読者が持っている唯一の情報は期待そのものです。したがって、コンテキストがすべての読者に十分に理解されている可能性が高く、説明の例が実際には必要ない場合にのみ、暗黙のサブジェクトを使用することが役立ちます。標準的なケースは、shouldaマッチャーを使用してActiveRecord検証をテストすることです。
describe Article do
it { is_expected.to validate_presence_of(:title) }
end
明示的な匿名subject
(subject
名前なしで定義)は、読者がインスタンス化された方法を確認できるため、少し優れていますが、
名前付きサブジェクトは意図を明らかにする名前を提供しlet
ますが、変数の代わりに名前付きサブジェクトを使用する唯一の理由は、匿名サブジェクトを時々使用したい場合であり、匿名サブジェクトが理解しにくい理由を説明しました。
したがって、明示的な匿名subject
または名前付きの件名の合法的な使用は非常にまれです。
let
変数let
変数は、2つの違いを除いて、名前付きサブジェクトと同じです。
let
/let!
の代わりにsubject
/subject!
subject
たり、暗黙的に期待を呼び出すことを許可したりしません。let
例間の重複を減らすために使用することは完全に合法です。ただし、テストの明確さを犠牲にしない場合にのみ行ってください。使用するのに最も安全な時期let
は、let
変数の目的がその名前から完全に明確であり(したがって、読者が各例を理解するために、何行も離れている可能性がある定義を見つける必要がない)、同じように使用される場合です。すべての例で。これらのいずれかが当てはまらない場合は、単純な古いローカル変数でオブジェクトを定義するか、例の中でファクトリメソッドを呼び出すことを検討してください。
let!
それは怠惰ではないので、危険です。誰かがを含むサンプルグループにサンプルを追加したlet!
が、サンプルにlet!
変数が必要ない場合、
let!
変数を見て、それが例に影響を与えるかどうか、またどのように影響するのか疑問に思うため、その例は理解しにくいでしょう。let!
変数の作成に時間がかかるため、例は必要以上に遅くなりますしたがってlet!
、仮にあったとしても、将来のサンプル作成者がその罠に陥る可能性が低い、小さくて単純なサンプルグループでのみ使用してください。
let
個別に説明する価値のある主題または変数の一般的な乱用があります。一部の人々はこのようにそれらを使用するのが好きです:
describe 'Calculator' do
describe '#calculate' do
subject { Calculator.calculate }
it { is_expected.to be >= 0 }
it { is_expected.to be <= 9 }
end
end
(これは、2つの期待値が必要な数値を返すメソッドの単純な例ですが、メソッドが多くの期待値を必要とする、および/または多くの副作用があるより複雑な値を返す場合、このスタイルにはさらに多くの例/期待値があります。すべて期待が必要です。)
人々は、例ごとに1つの期待値しか持たない(例ごとに1つのメソッド呼び出しのみをテストする必要があるという有効なルールと混同されている)と聞いたため、またはRSpecのトリッキーさに恋をしているためにこれを行います。匿名または名前付きの件名またはlet
変数を使用するかどうかにかかわらず、それを行わないでください!このスタイルにはいくつかの問題があります。
代わりに、次の1つの例を記述します。
describe 'Calculator' do
describe '#calculate' do
it "returns a single-digit number" do
result = Calculator.calculate
expect(result).to be >= 0
expect(result).to be <= 9
end
end
end
:aggregate_failures
ような行でタグを使用できますit "marks a task complete", :aggregate_failures do
(Rails 5 Test Prescriptionsの本から引用)
expect(result).to be_between(0, 9)
。
expect(result.to_s).to match(/^[0-9]$/)
-醜いことはわかっていますが、実際にあなたが言っていることをテストするか、おそらくbetween
+を使用しis_a? Integer
ますが、ここではテストしていますタイプも。そして、ただlet
..それは懸念の対象ではないはずです、そして実際には例の間で値を再評価する方が良いかもしれません。それ以外の場合は、投稿に+1
let!
は自分のチームメートを自分で納得させることの危険性についてのあなたの説明が大好きです。この回答を送信します。
Subject
そしてlet
あなたあなたのテスト整頓アップと速度を支援するだけのツールです。rspecコミュニティの人々はそれらを使用しているので、それらを使用しても大丈夫かどうかについて心配する必要はありません。それらは同様に使用できますが、わずかに異なる目的を果たします
Subject
テスト対象を宣言し、その後、それを次のテストケースにいくつでも再利用できます。これにより、コードの繰り返しが減ります(コードの乾燥)
Let
に代わるものです before: each
テストデータをインスタンス変数に割り当てるブロックです。 Let
いくつかの利点があります。まず、インスタンス変数に割り当てずに値をキャッシュします。次に、遅延評価されます。つまり、仕様で要求されるまで評価されません。したがってlet
、テストをスピードアップするのに役立ちます。またlet
、読みやすいと思います
subject
テスト対象であり、通常はインスタンスまたはクラスです。let
テストで変数を割り当てるためのものであり、インスタンス変数を使用するのではなく、遅延して評価されます。このスレッドにはいくつかの良い例があります。