私はモックオブジェクトに不慣れで、RSpecでそれらを使用する方法を学ぼうとしています。誰かが例(hello RSpecモックオブジェクトワールドタイプの例)、またはRSpecモックオブジェクトAPIの使用方法に関するリンク(またはその他のリファレンス)を投稿できますか?
5 に答える
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
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
回答にコメントを投稿するのに十分なポイントがありませんが、受け入れられた回答は、ランダムな値をスタブする方法を理解するのにも役立ちました。
たとえば、ランダムに割り当てられたオブジェクトのインスタンス値をスタブできるようにする必要がありました。
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パスと失敗をまだ取得していました。
ブライアンありがとう
現在の(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
)モック構文を使用しています。これは任意のオブジェクトで機能します。mock_model
受け入れられた答えは、 ActiveModelモデルに固有であり、rspec-railsから別のgemに移動された古いrspec-railsメソッドを使用しています。
通常、一部の機能を他のオブジェクトに委任したいが、現在のテストで実際の機能をテストしたくない場合は、モックオブジェクトを使用するため、そのオブジェクトを制御しやすい他のオブジェクトに置き換えます。このオブジェクトを「依存関係」と呼びましょう...
テストしているもの(オブジェクト/メソッド/関数...)は、メソッドを呼び出してこの依存関係と相互作用できます...
- 何かをクエリします。
- 何かを変更するか、何らかの副作用を引き起こします。
メソッドを呼び出して何かを照会する場合
依存関係を使用して何かを「クエリ」する場合、通常のオブジェクトを使用して、テストするオブジェクトで期待される出力をテストできるため、「モック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