17

私は ActiveRecord モデル、PricePackage を持っています。これには before_create コールバックがあります。このコールバックは、サードパーティ API を使用してリモート接続を確立します。私は factory girl を使用しており、テスト中に新しいファクトリが構築されたときにリモート呼び出しが行われないように、この API をスタブ化したいと考えています。

モックとスタブに Rspec を使用しています。私が抱えている問題は、私のfactory.rb内でRspecメソッドが利用できないことです.

モデル:

class PricePackage < ActiveRecord::Base
    has_many :users
    before_create :register_with_3rdparty

    attr_accessible :price, :price_in_dollars, :price_in_cents, :title


    def register_with_3rdparty
      return true if self.price.nil?

        begin
          3rdPartyClass::Plan.create(
            :amount => self.price_in_cents,
            :interval => 'month',
            :name => "#{::Rails.env} Item #{self.title}",
            :currency => 'usd',
            :id => self.title)
        rescue Exception => ex
          puts "stripe exception #{self.title} #{ex}, using existing price"
          plan = 3rdPartyClass::Plan.retrieve(self.title)
          self.price_in_cents = plan.amount
          return true
        end
    end

工場:

#PricePackage
Factory.define :price_package do |f|
  f.title "test_package"
  f.price_in_cents "500"
  f.max_domains "20"
  f.max_users "4"
  f.max_apps "10"
  f.after_build do |pp|
    #
    #heres where would like to mock out the 3rd party response
    #
    3rd_party = mock()
    3rd_party.stub!(:amount).price_in_cents
    3rdPartyClass::Plan.stub!(:create).and_return(3rd_party)
  end
end

rspec モックとスタブ ヘルパーを factory.rb にロードする方法がわかりません。これは、これを処理する最善の方法ではない可能性があります。

4

6 に答える 6

20

VCR gem の作成者として、おそらく、このような場合に VCR gem を推奨することを期待するでしょう。HTTP に依存するコードのテストには確かにお勧めしますが、設計には根本的な問題があると思います。TDD (テスト駆動開発) は設計分野であることを忘れないでください。何かを簡単にテストするのが面倒だと感じた場合、それは設計について何かを伝えていることになります。あなたのテストの痛みを聞いてください!

この場合、あなたのモデルにはサードパーティの API 呼び出しを行うビジネスはないと思います。これは、単一責任の原則に対する重大な違反です。モデルは一部のデータの検証と永続化を担当する必要がありますが、これは間違いなくそれを超えています。

代わりに、サード パーティの API 呼び出しをオブザーバーに移動することをお勧めします。Pat Maddox は、オブザーバーを使用して、SRP (単一責任の原則) に違反することなく物事を疎結合する方法と、それによってテストがはるかに簡単になり、設計が改善される方法について説明している素晴らしいブログ記事を投稿しています。

それをオブザーバーに移動したら、単体テストでオブザーバーを無効にするのは簡単ですが (そのオブザーバーの特定のテストを除く)、本番環境と統合テストでは有効のままにしておきます。Pat のno-peeping-tomsプラグインを使用してこれを支援できます。または、Rails 3.1 を使用している場合は、observer を簡単に有効/無効にできるActiveModel に組み込まれた新しい機能を確認する必要があります。

于 2011-10-22T18:44:57.023 に答える
2

VCR gem (https://www.relishapp.com/myronmarston/vcr) をチェックしてください。テスト スイートの HTTP インタラクションを記録し、再生します。サードパーティの API への HTTP 接続を実際に行う必要がなくなります。これは、対話を手動でモックするよりもはるかに簡単なアプローチであることがわかりました。これは、Foursquare ライブラリを使用した例です。

VCR.config do |c|
  c.cassette_library_dir = 'test/cassettes'
  c.stub_with :faraday
end

describe Checkin do
  it 'must check you in to a location' do
    VCR.use_cassette('foursquare_checkin') do
      Skittles.checkin('abcd1234') # Doesn't actually make any HTTP calls.
                                   # Just plays back the foursquare_checkin VCR
                                   # cassette.
    end
  end
end
于 2011-10-08T10:53:45.623 に答える
1

カプセル化という点では魅力があると思いますが、ファクトリ内でサード パーティのスタブ化を行う必要はありません (ある意味では、行うべきではありません)。

ファクトリにカプセル化する代わりに、RSpec テストの開始時に単純に定義できます。これを行うと、テストの前提が明確になり、最初に記述されます (これはデバッグ時に非常に役立ちます)。

PricePlan を使用するテストの前に、必要な応答をセットアップしてから、サードパーティの.createメソッドから返します。

before(:all) do
  3rd_party = mock('ThirdParty')
  3rdPartyClass::Plan.stub(:create).and_return(true)
end  

これにより、メソッドを呼び出すことができるようになりますが、リモート呼び出しから離れてしまいます。

*サードパーティのスタブには元のオブジェクト (:price_in_cents) への依存関係があるようですが、正確な依存関係について詳しく知らないため、適切なスタブが何であるかを推測できません (または、必要な場合)*

于 2011-10-10T13:34:24.607 に答える
0

FactoryGirl はオブジェクトの属性をスタブ化できます。

# Returns an object with all defined attributes stubbed out
stub = FactoryGirl.build_stubbed(:user)

詳細については、FactoryGirl の rdocsを参照してください。

于 2011-10-09T14:28:15.690 に答える
0

私はまったく同じ問題を抱えていました。オブザーバーの議論はさておき(それは正しいアプローチかもしれません)、これが私にとってうまくいったことです(これは出発点であり、改善できる/改善する必要があります):

次の内容のファイル 3rdparty.rb を spec/support に追加します。

RSpec.configure do |config|
  config.before do
    stub(3rdPartyClass::Plan).create do
     [add stuff here]
    end
  end
end

そして、あなたの spec_helper.rb がこれを持っていることを確認してください:

  Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
于 2012-01-31T00:03:34.623 に答える
-1

さて、まず、あなたは「モックとスタブ」がファクトリーガールの言語ではないということは正しいです

モデルの関係を推測すると、別のオブジェクトファクトリを構築し、そのプロパティを設定してから、それらを関連付ける必要があると思います。

#PricePackage
Factory.define :price_package do |f|
  f.title "test_package"
  f.price_in_cents "500"
  f.max_domains "20"
  f.max_users "4"
  f.max_apps "10"
  f.after_build do |pp|
  f.3rdClass { Factory(:3rd_party) }
end

Factory.define :3rd_party do |tp|
  tp.price_in_cents = 1000
end

うまくいけば、私は関係を判読不能に壊さなかった。

于 2011-09-26T22:22:30.747 に答える