【问题标题】:How do I test the behavior inside an ActiveRecord creation block?如何测试 ActiveRecord 创建块内的行为?
【发布时间】:2012-10-21 17:23:30
【问题描述】:

如何使用 rspec 测试这样的代码?

Foo.create! do |foo|
  foo.description = "thing"
end

我不想测试对象是否已创建——我想测试是否使用正确的对象调用了正确的方法。相当于测试这个:

Foo.create!(description: "thing")

用这个:

Foo.should_receive(:create!).with(description: "thing")

【问题讨论】:

  • 有些东西不需要测试,除非描述是自定义方法,或者这是学术兴趣?
  • 我需要确保我的客户端代码将正确的对象分配给正确的属性

标签: ruby-on-rails ruby activerecord rspec


【解决方案1】:

这就是你所追求的吗?

it "sets the description" do
  f = double
  Foo.should_receive(:create!).and_yield(f)
  f.should_receive(:description=).with("thing")

  Something.method_to_test
end

【讨论】:

    【解决方案2】:
    Foo.count.should == 1
    Foo.first.description.should == 'thing'
    

    【讨论】:

    • 但我不想测试底层的持久性行为——我想测试代码是否将正确的对象设置到正确的位置。我现在为我的问题添加了更多细节。
    • “我想测试是否使用正确的对象调用了正确的方法。”您可以通过指定结果状态来做到这一点,如@antiqe 的示例中所示。通过指定使用 description=write_attribute(:description, "value") 或您可以使用的任何其他替代方案,您认为您会获得什么好处?
    • @DavidChelimsky 的目标是不测试 AR 创建的持久性。我知道我正在测试的每个方法都可以正常工作,所以为了测试使用它们的函数,我可以测试它们是否被调用。我知道这不是那么漂亮,而且新的热点似乎是从不做控制器规格——只有响应和/或集成。但无论如何回到你的观点 - 是的,这是真的,两种方法都会有相同的行为,所以我应该测试它们的结果。所以我猜 FG build_stubbed 和测试结果值可能是一个很好的整体解决方案。想法?
    • err,忘记我对 build_stubbed 的评论,显然在这里不适用,因为我正在测试创建。但其他的想法仍然存在。
    【解决方案3】:

    这是一种结合了@antiqe 和@Fitzsimmons 答案中的最佳答案的组合方法。不过它要冗长得多。

    这个想法是以更像 AR::Base.create 的方式模拟 Foo.create。首先,我们定义一个辅助类:

    class Creator
      def initialize(stub)
        @stub = stub
      end
    
      def create(attributes={}, &blk)
        attributes.each do |attr, value|
          @stub.public_send("#{attr}=", value)
        end
    
        blk.call @stub if blk
    
        @stub
      end
    end
    

    然后我们可以在我们的规范中使用它:

    it "sets the description" do
      f = stub_model(Foo)
      stub_const("Foo", Creator.new(f))
    
      Something.method_to_test
    
      f.description.should == "thing"
    end
    

    您也可以使用FactoryGirl.build_stubbed 代替stub_model。但是,您不能使用mock_modelmockdouble,因为您会再次遇到同样的问题。

    现在您的规范将通过以下任何代码 sn-ps:

    Foo.create(description: "thing")
    
    Foo.create do |foo|
      foo.descrption = "thing"
    end
    
    foo = Foo.create
    foo.descrption = "thing"
    

    非常感谢您的反馈!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-02
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      相关资源
      最近更新 更多