web-dev-qa-db-ja.com

RSpecモックオブジェクトの例

私はオブジェクトをモックするのが初めてで、RSpecでそれらを使用する方法を学ぼうとしています。誰かが例(こんにちは、RSpecモックオブジェクトワールドタイプの例)、またはRSpecモックオブジェクトAPIの使用方法に関するリンク(またはその他の参照)を投稿してください。

37
agentbanks217

Railsアプリケーションでのコントローラーテストのために行った簡単なモックの例を次に示します。

before(:each) do
  @page = mock_model(Page)
  @page.stub!(:path)
  @page.stub!(:find_by_id)
  @page_type = mock_model(PageType)
  @page_type.stub!(:name)
  @page.stub!(:page_type).and_return(@page_type)
end

この場合、Page&PageTypeモデル(オブジェクト)をモックし、呼び出すメソッドの一部をスタブします。

これにより、次のようなテストを実行できます。

it "should be successful" do
  Page.should_receive(:find_by_id).and_return(@page)
  get 'show', :id => 1
  response.should be_success
end

この答えは、より多くのRails具体的ですが、少しでもお役に立てば幸いです。


編集

わかりましたので、ここでこんにちは世界の例です...

次のスクリプト(hello.rb)を考えます:

class Hello
  def say
    "hello world"
  end
end

次の仕様(hello_spec.rb)を作成できます。

require 'rubygems'
require 'spec'

require File.dirname(__FILE__) + '/hello.rb'

describe Hello do
  context "saying hello" do 
    before(:each) do
      @hello = mock(Hello)
      @hello.stub!(:say).and_return("hello world")
    end

    it "#say should return hello world" do
      @hello.should_receive(:say).and_return("hello world")
      answer = @hello.say
      answer.should match("hello world")
    end
  end
end
64
Brian

mockは、このgithub pull に基づいて非推奨になりました。

代わりにdoubleを使用できます-more here ...

 before(:each) do
   @page = double("Page")
   end

  it "page should return hello world" do
    allow(@page).to receive(:say).and_return("hello world")
    answer = @page.say
    expect(answer).to eq("hello world")
  end
6
tokhi

回答にコメントを投稿するのに十分なポイントがありませんが、受け入れられた回答は、ランダムな値をスタブ化する方法を理解しようとするのにも役立ちました。

たとえば、ランダムに割り当てられたオブジェクトのインスタンス値をスタブできるようにする必要がありました。

class ClumsyPlayer < Player do

  def initialize(name, health = 100)
    super(name, health)
    @health_boost = Rand(1..10)
  end
end

それから私の仕様では、不器用なプレイヤーのランダムなヘルスをスタブして、回復したときに適切なブーストが得られることをテストする方法を見つけるのに問題がありました。

秘wasは:

@player.stub!(health_boost: 5)

そのため stub!が鍵でした。私はstubを使用していましたが、それでもランダムなrspecのパスと失敗が発生していました。

ブライアンありがとう

5
JoeManFoo

通常、一部の機能を他のオブジェクトに委任したいが、現在のテストで実際の機能をテストしたくない場合は、モックオブジェクトを使用します。そのため、そのオブジェクトを制御しやすい他のオブジェクトに置き換えます。このオブジェクトを「依存関係」と呼びましょう...

テストしているもの(オブジェクト/メソッド/関数...)は、メソッドを呼び出すことでこの依存関係と対話できます...

  • 何かを照会します。
  • 何かを変更するか、何らかの副作用を引き起こします。

メソッドを呼び出して何かを照会するとき

何かの「クエリ」への依存関係を使用している場合、「モックAPI」を使用する必要はありません。通常のオブジェクトを使用するだけで、テスト対象のオブジェクトで期待される出力をテストできます。例えば:

describe "Books catalog" do
  class FakeDB
    def initialize(books:)
      @books = books
    end

    def fetch_books
      @books
    end
  end

  it "has the stored books" do
    db = FakeDB.new(books: ["Principito"])
    catalog = BooksCatalog.new(db)
    expect(catalog.books).to eq ["Principito"]
  end
end

メソッドを呼び出して何かを変更したり、何らかの副作用を引き起こす場合...

依存関係を変更したり、データベースに新しいレコードを挿入したり、メールを送信したり、支払いを行ったりするなどの副作用で何かをしたい場合は、変更または副作用が発生したことをテストする代わりに、適切な属性を持つ適切な関数/メソッドを呼び出していることを確認するだけです。例えば:

describe "Books catalog" do
  class FakeDB
    def self.insert(book)
    end
  end

  def db
    FakeDB
  end

  it "stores new added books" do
    catalog = BooksCatalog.new(db)

    # This is how you can use the Mock API of rspec
    expect(db).to receive(:insert).with("Harry Potter")

    catalog.add_book("Harry Potter")
  end
end

これは基本的な例ですが、この知識で多くのことができます=)

このコンテンツを含む投稿を作成しましたが、もう少し役立つかもしれません http://bhserna.com/2018/how-and-when-to-use-mock -objects-with-Ruby-and-rspec.html

1
Benito Serna

現在の(3.x)RSpecは、純粋なモックオブジェクト( tokhiの答え のように)と部分的なモック(既存のオブジェクトへの呼び出しのモック)の両方を提供します。部分的なモックの例を次に示します。 expectreceiveを使用してOrderCreditCardServiceへの呼び出しをモックするため、実際に呼び出しを行わなくても呼び出しが行われた場合にのみテストに合格します。それ。

class Order
  def cancel
     CreditCardService.instance.refund transaction_id
  end
end

describe Order do
  describe '#cancel' do
    it "refunds the money" do
      order = Order.new
      order.transaction_id = "transaction_id"
      expect(CreditCardService.instance).to receive(:refund).with("transaction_id")
      order.cancel
    end
  end
end

この例では、モックはCreditCardService.instanceの戻り値に基づいています。これはおそらくシングルトンです。

withはオプションです。これがなければ、refundを呼び出すと期待どおりになります。戻り値はand_returnで指定できます。この例では使用されていないため、呼び出しはnilを返します。


この例では、RSpecの現在の(expect .to receive)モック構文を使用します。これは任意のオブジェクトで機能します。受け入れられた回答は、ActiveModelモデルに固有であり、rspec-Railsから別のgemに移動された古いrspec-Rails mock_modelメソッドを使用します。

1