私はオブジェクトをモックするのが初めてで、RSpecでそれらを使用する方法を学ぼうとしています。誰かが例(こんにちは、RSpecモックオブジェクトワールドタイプの例)、またはRSpecモックオブジェクトAPIの使用方法に関するリンク(またはその他の参照)を投稿してください。
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
回答にコメントを投稿するのに十分なポイントがありませんが、受け入れられた回答は、ランダムな値をスタブ化する方法を理解しようとするのにも役立ちました。
たとえば、ランダムに割り当てられたオブジェクトのインスタンス値をスタブできるようにする必要がありました。
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のパスと失敗が発生していました。
ブライアンありがとう
通常、一部の機能を他のオブジェクトに委任したいが、現在のテストで実際の機能をテストしたくない場合は、モックオブジェクトを使用します。そのため、そのオブジェクトを制御しやすい他のオブジェクトに置き換えます。このオブジェクトを「依存関係」と呼びましょう...
テストしているもの(オブジェクト/メソッド/関数...)は、メソッドを呼び出すことでこの依存関係と対話できます...
何かの「クエリ」への依存関係を使用している場合、「モック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
現在の(3.x)RSpecは、純粋なモックオブジェクト( tokhiの答え のように)と部分的なモック(既存のオブジェクトへの呼び出しのモック)の両方を提供します。部分的なモックの例を次に示します。 expect
とreceive
を使用してOrder
のCreditCardService
への呼び出しをモックするため、実際に呼び出しを行わなくても呼び出しが行われた場合にのみテストに合格します。それ。
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
メソッドを使用します。