38

私はモックオブジェクトに不慣れで、RSpecでそれらを使用する方法を学ぼうとしています。誰かが例(hello RSpecモックオブジェクトワールドタイプの例)、またはRSpecモックオブジェクトAPIの使用方法に関するリンク(またはその他のリファレンス)を投稿できますか?

4

5 に答える 5

64

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

私はこの答えがよりレールに固有であることを知っていますが、それが少しあなたを助けることを願っています。


編集

さて、これがHelloWorldの例です...

次のスクリプト(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
于 2010-09-01T22:58:18.237 に答える
7

mockこのgithubプルに基づいて非推奨になりました。

今では代わりに使用できますdouble-詳細はこちら...

 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
于 2016-09-19T12:45:17.873 に答える
5

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

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

class ClumsyPlayer < Player do

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

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

秘訣は:

@player.stub!(health_boost: 5)

それstub!が鍵でした。私はちょうど使用していてstub、ランダムなrspecパスと失敗をまだ取得していました。

ブライアンありがとう

于 2013-04-14T19:32:39.397 に答える
1

現在の(3.x)RSpecは、純粋なモックオブジェクト(tokhiの回答のように)と部分的なモック(既存のオブジェクトへのモック呼び出し)の両方を提供します。部分的なモックの例を次に示します。とを使用expectしての呼び出しreceiveをモックするため、実際に呼び出しを行わなくても呼び出しが行われた場合にのみテストに合格します。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)モック構文を使用しています。これは任意のオブジェクトで機能します。mock_model受け入れられた答えは、 ActiveModelモデルに固有であり、rspec-railsから別のgemに移動された古いrspec-railsメソッドを使用しています。

于 2016-08-27T22:02:00.087 に答える
1

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

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

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

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

依存関係を使用して何かを「クエリ」する場合、通常のオブジェクトを使用して、テストするオブジェクトで期待される出力をテストできるため、「モック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

于 2018-04-10T02:16:33.983 に答える