【问题标题】:Why does the wrong object get tested in this RSpec setup?为什么在此 RSpec 设置中测试了错误的对象?
【发布时间】:2016-11-01 14:03:22
【问题描述】:

我在进行 RSpec 测试时遇到问题,我怀疑这可能与我在 before 块中明确使用主题有关。值得注意的是,我正在测试具有 has_many / belongs_to 关系的 ActiveRecord 对象。这是我失败的测试,我试图根据添加孩子的事件断言父母有一些行为:

subject { FactoryGirl.create(:parent) }
let(:child) { FactoryGirl.build(:child) }

context "with added child object" do
  before { subject.children << child }
  its(:foo) { is.expected_to eq("bar")
end

在我的父模型中,我有一些基于添加在测试之外工作的子记录的简单逻辑。由于它在测试中不起作用,我转而将规范部分写成长格式以尝试了解原因:

before do
  puts "subject is #{subject}"
  puts "child is #{child}"
  subject.children << child 
  puts "#{child} is now attached to #{child.parent}"
end

it "has the correct response" do
  puts "testing against subject #{subject}"
  expect(subject.foo).to eq("bar")
end

我得到的输出表明正在发生一些奇怪的事情 - 我附加孩子的主题与设置和测试块中的主题不同:

subject is #<Parent:0x00561eddf1a7a0>                                                  
child is #<Child:0x00561edcdd7fb0>
#<Child:0x00561edcdd7fb0> is now attached to #<Parent:0x00561edd11c040>
testing against subject #<Parent:0x00561eddf1a7a0>

我是否对导致这种行为的主题做错了什么?有没有更好的方法来编写这个测试?

根据以下建议更新

当我像这样构建测试时,它通过了,并且输出不包含任何神秘的第二个父版本。

before do
  child = FactoryGirl.create(:child, parent: parent)      
end

it "has the correct response" do
  # some puts to check the states of the various models here
  expect(subject.foo).to eq("bar")
end

但是,这不是客户使用该类的方式 - 可以通过多种不同的方法添加子级,我希望模型无论如何都以相同的方式运行。

这也没有回答问题 - 第一次设置中额外的对象来自哪里?

【问题讨论】:

  • 我不明白你在测试什么? foo 方法对孩子有什么作用?将孩子添加到父母不会使其成为主题。主题仍然是父母,发生的事情就是我期望发生的事情。
  • @dexx 我正在测试父方法之一的行为,基于添加子时触发的事件。我希望主题仍然是父母。为什么您期望在测试中创建第二个父对象,子对象会依附于该对象?或者,也许我对在问题中强调这一点不够清楚。
  • 我现在看到了问题,我正在查看主题并针对主题放置进行测试。工厂里有什么给孩子的? child_to_attach 是错字吗?还是其他让/方法?
  • @j-dexx 对不起,这确实是一个错字。子工厂非常简单,只需设置几个必填字段。
  • 是父对象之一吗?

标签: ruby-on-rails ruby testing activerecord rspec


【解决方案1】:

你可以这样试试吗:

let(:parent) { FactoryGirl.create(:parent) }
let(:child) { FactoryGirl.build(:child) }
subject { parent }

context "with added child object" do
  before { parent.children << child }
  its(:foo) { is.expected_to eq("bar")
end

或者如果子对象与父对象有关系,那么:

let!(:parent) { FactoryGirl.create(:parent) }
let!(:child) { FactoryGirl.build(:child, parent: parent) }
subject { parent }

context "with added child object" do
  its(:foo) { is.expected_to eq("bar")
end

让我知道结果。

【讨论】:

  • 对于第一个示例,我们使用存储桶运算符进行分配,我最终得到与以前相同的行为:测试失败,并且孩子最终得到一个完全不同的父母(我不明白为什么)。
  • 对于第二个示例,它是相同的 - 除非我 create 而不是 build 孩子,在这种情况下测试通过(!)并且孩子最终正确连接。该存储桶分配似乎出了点问题,但我不确定是什么。
  • 可能你需要在parent.children &lt;&lt; child之后做parent.save!
  • 如果你在父类和子类之间有关系,我相信第二种方法更适合这种情况。将build 替换为create
  • 您在定义关联时是否添加了选项autosave: true?见此链接:api.rubyonrails.org/classes/ActiveRecord/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 2023-03-24
  • 2010-11-29
  • 2013-07-10
相关资源
最近更新 更多