RSpecモックの使用方法(ステップバイステップチュートリアル)
RSpecのモックとは何ですか?
(または、これはRSpecに固有の概念ではないため、一般的なモックです。)
モックはテストに使用されるオブジェクトです 。
モックを使用して、2つのオブジェクト間の相互作用をテストします。通常の予想のように出力値をテストする代わりに。
例 :
画像を反転させるAPIを作成しています。
独自の画像操作コードを作成する代わりに、 mini_magick
のようなgemを使用します 。
コードとこの外部依存関係の間の相互作用をテストしたい …したがって、 ImageProcessor
で正しいメソッドが呼び出されることを期待するモックを作成します。 クラス。
これは、テストを実行するたびに画像を反転する(遅い操作)ことがないことを意味します。
それはどのように機能しますか?
モックは元のオブジェクトを置き換えるため、実際のメソッドは呼び出されません。
いくつかのコード例の時間です!
RSpecモックの例
これがImageFlipper
です テスト:
RSpec.describe "ImageFlipper" do it "calls the flip method with the correct arguments" do mock = double("mini_magick") expect(mock).to receive(:flip).with("ruby.jpg") img = ImageFlipper.new(mock) img.flip("ruby.jpg") end end
このテストでは、TDDを使用してコードを記述できます。
最初 :
ImageFlipper
を作成する必要があります クラス。
このように :
class ImageFlipper def initialize(image_processor) @image_processor = image_processor end end
フリップ
も必要です 方法:
def flip(file_name) end
これで、RSpecからこのフィードバックを受け取ります:
Failures: 1) ImageFlipper calls the flip method with the correct arguments Failure/Error: expect(mock).to receive(:flip).with("ruby.jpg") (Double "mini_magick").flip("ruby.jpg") expected: 1 time with arguments: ("ruby.jpg") received: 0 times # ./rspec-mocks.rb:6:in `block (2 levels) in <top (required)>'
これは、フリップコード>ということです メソッドは0回呼び出されましたが、1回呼び出されると予想されていました。
必要なものを与えることで、このテストに合格することができます :
def flip(file_name) @image_processor.flip(file_name) end
さあ、合格テストがあります :
. Finished in 0.00751 seconds (files took 0.11157 seconds to load) 1 example, 0 failures
復習しましょう:ここで何をしましたか?
ImageFlipper
を作成しました image_processor
を取るクラス 。
このプロセッサはflip
に応答します メソッド。
モックを使用して、このメソッドが引数付きで1回呼び出されたかどうかをテストします。
わかっています。
この例は単純です。
しかし、 ImageFlipper
の完全な実装を想像することができます ファイルが存在するかどうか、有効な画像かどうかなどを確認します。
モックテストとバリューテストの違い
通常のテストでは、メソッドの戻り値を確認します :
「このメソッドは反転した画像を返しましたか?」
モックを使用する場合、動作をテストしています :
「私たちは、適切な情報と正確に適切な回数で、他の人に正しいことを伝えましたか?」
モックとスタブ
もう1つの混乱点は、モックとスタブの比較です。
違いは何ですか?
- スタブは、応答が定型化されたメソッドにすぎず、動作は関係ありません。
- モックは、メソッドが呼び出されない場合、メソッドが呼び出されることを想定しています。テストは失敗します。
これがRSpecのスタブです :
stub = double("json") allow(stub).to receive(:response) do {"blog"=>"rubyguides.com", "rating"=>"5/5"}.to_json end
allow
メソッドがこれをスタブにします。
テストオブジェクトdouble( "json")
を許可しています このメソッドを受信して応答しますが、呼び出されているかどうかは確認していません 。
それが違いです!
検証済みダブルの使用方法
モックとスタブの欠点の1つは、本番コードに存在しないメソッドを使用してしまう可能性があることです。
メソッド名が変更されたため…またはタイプミスをした可能性があります!
確認済みのダブルスに会う 。
検証済みのdoubleは、スタブ( allow
)として使用できます。 )またはモック( expect
)&この名前のメソッドが存在することを確認します。
例 :
mock = instance_double(ImageProcessor)
メソッドが存在しない場合、これによりエラーが発生します:
1) ImageFlipper calls the flip method with the correct arguments Failure/Error: expect(mock).to receive(:flip).with("ruby.jpg") the ImageProcessor class does not implement the instance method: flip
ただし、メソッドが存在する場合は正しく機能します。
モックの戻り値
モッキングに戻りましょう。
最後の例 これがありました:
expect(mock).to receive(:flip).with("ruby.jpg")
コードがflip
を呼び出すとき 、モックは nil
を返します 。
コードがnil以外の値を期待している場合、これはエラーになります。
モックに結果を返すようにすることで、これを修正できます。
このように :
expect(mock).to receive(:flip).with("ruby.jpg").and_return("ruby-flipped.jpg")
インスタンスメソッドをモックする方法
次のようなコードがあるとします:
class NumberGenerator def random "A" * rand(1..10) end end
この方法はランダムであるため、テストが困難です。
RSpecを使用すると、 rand
をモックまたはスタブすることができます 。
このように :
it "generates a random number" do generator = NumberGenerator.new allow(generator).to receive(:rand).and_return(5) expect(generator.random).to eq("AAAAA") end>
今 :
rand
メソッドの結果をテストするために使用できるように、固定値を返します。
理想的には、依存関係( rand
)を挿入する必要があります 関数、この場合)あなたがそれを制御できるように。依存関係を挿入するということは、パラメータとして渡すことを意味します 、何も派手ではありません。
ただし、メソッドをスタブするだけの方が便利な場合もあります。
モックを使用するタイミング
さて、大きな質問です…
正確にいつモックを使用する必要がありますか?
ソフトウェア開発は複雑なトピックです。
ただし、従うことができるいくつかのガイドラインがあります :
- テスト対象のメソッドが値を返し、副作用(ファイルの作成、APIリクエストの作成など)がない場合は、モックは必要ありません。戻り値を確認するだけです。
- メソッドが外部オブジェクトを操作して注文を送信している場合は、これらのオブジェクトとの相互作用をモックできます。
- メソッドが外部サービス(APIなど)からのデータをリクエストしている場合は、スタブを使用してテスト目的でこのデータを提供できます。
外の世界とのやり取りのためにモックを予約する 。
言い換えれば…
独自のアプリケーションのクラスをあざけるのは避けてください!
なぜですか?
これにより、テストと実装の詳細の結合が促進され、コードの変更が困難になります 。
唯一の例外は、サードパーティのコードのラッパーであるクラスです。
詳細については、このビデオをご覧ください :
概要
RSpecモック、スタブ、検証済みのダブルについて学習しました!
この記事を共有してください そのため、より多くの人々がこのコンテンツを楽しんで利益を得ることができます。
読んでくれてありがとう🙂
-
Ruby Mapメソッドの使用方法(例付き)
Mapは、配列、ハッシュ、範囲で使用できるRubyメソッドです。 マップの主な用途は、データを変換することです。 例 : 文字列の配列が与えられた場合、すべての文字列に目を通し、すべての文字を大文字にすることができます。 または、Userのリストがある場合 オブジェクト… 変換できます 対応するメールアドレス、電話番号、またはその他の属性のリストにそれらを追加します Userで定義 クラス。 これを行う方法を正確に見てみましょう! ルビーマップ構文 マップの構文は次のようになります: array = [a, b, c] array.map { |string| string.
-
Rubyスレッドの使用方法:わかりやすいチュートリアル
Rubyのスレッドとは何ですか? スレッドにより、Rubyプログラムは同時に複数のことを実行できます。 次のようなもの : 複数のファイルを読み取る 複数のウェブリクエストの処理 複数のAPI接続を確立する スレッドを使用した結果、マルチスレッドのRubyプログラムが作成され、作業をより迅速に行うことができます。 しかし、1つの警告… Rubyアプリケーションを実行するデフォルトの方法であるMRI(MatzのRuby Interpreter)では、 i/oバウンドアプリケーションを実行する場合にのみスレッドの恩恵を受けます。 。 この制限は、 GIL(グローバルインタープリター