2009-10-02 4 views
1

다음 사양은 작동하지만 이럴 수는 없습니다. 나는 rspec, 특히 mock과 stubs에 대해 머리를 쓰는 데 어려움을 겪고있다. 어떻게해야합니까?

모델 코드

class RecipeFermentable < ActiveRecord::Base 
    belongs_to :recipe 
    belongs_to :product 

    def set_attributes() 
    attrs = product.product_attributes 
    self.ppg = attrs.find_by_name(:ppg.to_s).value 
    self.ecb = attrs.find_by_name(:ecb.to_s).value 
    end 
end 

입니다 그리고 이것은 내가 내 사양 내 방법보다 훨씬 더 큰 시작을

it "should set the attributes from the product" do 
    @product_attribute1 = mock_model(ProductAttribute, :name => :ppg, :value => 40) 
    @product_attribute2 = mock_model(ProductAttribute, :name => :ecb, :value => 1) 

    @product = Product.new 
    @product.product_attributes << @product_attribute1 
    @product.product_attributes << @product_attribute2 
    @recipe_fermentable = RecipeFermentable.new 
    @recipe_fermentable.product.should_receive(:product_attributes).and_return(@product_attributes) 
    @product_attributes.stub(:find_by_name).with(:ppg.to_s).and_return(@product_attribute1) 
    @product_attributes.stub(:find_by_name).with(:ecb.to_s).and_return(@product_attribute2) 

    @recipe_fermentable.set_attributes 

    @recipe_fermentable.ppg.should eql(40) 
    @recipe_fermentable.ecb.should eql(1) 
end 

을 쓴 사양이고, 나는 진짜 제품을 사용하고 있습니다 . 이것에 대한 좋은 지침을 작성하는 길에있는 몇 가지 지침은 실제로 도움이 될 것입니다. 또한 누군가가 mocks와 스텁을 사용하여 rspec을 배우기에 좋은 리소스를 알고 있다면 링크를 추가 할 수 있습니까?

감사

답변

1

내가 여기에 몇 가지를 변경합니다 : 그것은 당신의 이전에 있어야합니다 귀하의 it의 코드의 대부분

  • 그냥 컨텍스트를 제공하고있다 (각) 블록을.
  • 메시지 예상을 설정하고 있지만 실제로 테스트하지 않는 것처럼 보입니다. 나는 기대가 stub로 바뀌어야한다고 생각한다. 또 다른 테스트는 it 'should call product_attributes' 일 수 있습니다. 실제로 그 기대를 테스트 할 것입니다. 구현을 테스트하고 동작을 테스트 할 것이기 때문에이 것을지지하지는 않지만 단지 요점을 만드는 것입니다.
  • 메시지 예상에서 @product_attributes를 반환하고 바로 뒤에서 find_by_name 호출을 스텁하기 위해 사용하고 있습니다. 그러나 @product_attributes는 정의하지 않았습니다. 나는 그것이 mock 객체 여야한다고 가정하고, 무엇이 이 실제로인지 알지 못합니다. 어쩌면 그것은 제로가 아니며, 당신은 그것에 몇 가지 방법을 스터핑하고 있습니다. 우리가 어디 두 변경

은 여기 : 방법의 모든 모든으로

before(:each) do 
    @product    = mock_model(Product) 
    @product_attribute_ppg = mock_model(ProductAttribute, :name => :ppg, :value => 40) 
    @product_attribute_ecb = mock_model(ProductAttribute, :name => :ecb, :value => 1) 
    @product_attributes  = mock('product_attributes') 
    @product_attributes.stub!(:find_by_name).with(:ppg.to_s).and_return(@product_attribute_ppg) 
    @product_attributes.stub!(:find_by_name).with(:ecb.to_s).and_return(@product_attribute_ecb) 
    @product.stub!(:product_attributes).and_return(@product_attributes) 

    @recipe_fermentable = RecipeFermentable.new 
    @recipe_fermentable.stub!(:product).and_return(@product) 
end 

it 'should set the attributes from the product' do 
    @recipe_fermentable.set_attributes 
    @recipe_fermentable.ppg.should eql(40) 
    @recipe_fermentable.ecb.should eql(1) 
end 

, 나는 완전히 여기에 당신의 접근 방식에 동의하지 않습니다. 나는 당신이 데이터를 반복하고 DB 정규화로부터 멀어지고 있다고 생각한다.

class RecipeFermentable < ActiveRecord::Base 
    def ppg 
    #rescue nil here so that if attributes is nil, or find_by_name('ppg') is nil, things don't blow up 
    product.attributes.find_by_name('ppg').value rescue nil 
    end 

    #other 
end 

테스트를위한 자원의 몇 :

    그위한 진짜 이유가없는 한 다음 대신 내가 제안, (당신의 방법 앞서 및 성능상의 이유로이 작업을 수행해야한다고 할 수있다)
  • RSpec book
  • xUnit patterns : RSpec 또는 Ruby가 아니지만 필수 항목입니다.
+0

감사합니다. 데이터를 복제하는 이유는 시간이 지남에 따라 제품 속성이 변경 될 수 있지만 제조법의 속성이 동일하게 유지되어야하기 때문입니다. 사용자가 변경하려고하지 않는 한. – Damian

+0

좋습니다. 당신이 그랬던 것처럼 속성을 저장하는 것이 틀림 없습니다. – hgmnz

관련 문제