3

私はこのクラスを持っています:

class EnablePost

  def initialize(post_klass, id)
    raise "oops" if post_klass.blank?
    @post_klass = post_klass 
    @id = id
  end

  def perform
    post = @post_klass.find_by_id(@id)
    return unless post
    post.update_attribute :enabled, true
  end

end

上記をテストするために私が書かなければならない仕様:

describe EnablePost do
  it "should enable a post" do
    post = mock
    post.should_receive(:blank?).and_return(false)
    post.should_receive(:find_by_id).with(22).and_return(post)
    post.should_receive(:update_attribute).with(:enabled, true)
    result = EnablePost.new(Post, 22).perform
    result.should be_true
  end
end

しかし、私が本当にやりたいことはEnablePost、ブラックボックスとして扱うことです。:blank?:find_by_idまたはをモックする必要はありません:update_attribute。つまり、仕様を次のようにしたいということです。

describe EnablePost do
  it "should enable a post" do
    post = mock
    result = EnablePost.new(post, 22).perform
    result.should be_true
  end
end

ここで何が欠けていますか?モックを間違って使用していますか?

4

1 に答える 1

2

はい、モックとスタブを混同しています。

良いモックの説明: http://jamesmead.org/talks/2007-07-09-introduction-to-mock-objects-in-ruby-at-lrug/

モック:

  • 人によって違うもの
  • あいまいな用語
  • Rails の「モック」との混同</li>

モック オブジェクト:

  • 事前に設定された予想されるメソッド呼び出し
  • 実際の呼び出しが期待されるものと一致することを確認します

http://martinfowler.com/articles/mocksArentStubs.htmlもチェックしてください[コメントのユーザー Zombies に感謝]

RSpec を使用している場合は、double、mock、および stub に別名が付けられます。RSpec は、コードを最も明確にするメソッド名を選択することを期待しています。

テスト コードの最初のチャンクは、「モック」という単語を正しく使用しています。呼び出されると予想されるメソッド呼び出しを事前に設定してから、それらを実行しています。

ただし、コードの 2 つの異なる領域をテストしています。最初の領域は初期化メソッドで、2 番目の領域は #perform メソッドです。

より小さなメソッドを作成すると、モックとスタブが簡単になる場合があります。

# What you want to test here is the raise and the member variables.
# You will stub the post_klass.
def initialize(post_klass, post_id)  # post_id is a better name
  raise "oops" if post_klass.blank?
  @post_klass = post_klass 
  @post_id = post_id  # because we don't want to mask Object#id
end

attr_accessor :post_id  
attr_accessor :post_klass

# What you want to test here is the post_klass calls #find_by_id with post_id.
# See we've changed from using instance variables to methods.
def post
  post_klass.find_by_id(post_id)
end

# What you want to test here is if the update happens.
# To test this, stub the #post method.
def perform
  p = post
  return unless p
  p.update_attribute :enabled, true
end

このようにコードを記述すると、#post メソッドのスタブが簡単になります。

モックとスタブの違いを示す RSpec のサンプル ソース コードについては、次を参照してください。

http://blog.firsthand.ca/2011/12/example-using-rspec-double-mock-and.html

于 2013-02-09T09:06:38.277 に答える