Rspec2 + Rails4:以部分形式测试显示的模型字段

时间:2013-07-23 09:23:35

标签: ruby-on-rails rspec2 ruby-on-rails-4 rspec-rails

问题

我想编写测试来检查我的“show”和“form”部分中显示的模型字段。我成功了“表演”,而不是“形式”。

主要约束:解决方案必须能够遍历包含模型字段的每个名称的数组。

我相信这个案例对于那些试图缩短他的测试脚本文件,同时拥有多个字段,并且完全控制显示内容和不显示内容的人来说非常有趣,所以我会努力寻找一个解决方案,如果您愿意,请帮助您:)

表单视图

没什么好看的

= form_for @user do |f|
  = f.select :field_1, options_from_collection_for_select ...
  = f.text_field :field_2
  ...

实际情况

我找到了一个简单的“show”部分方法,这是我的spec文件的样子:

def user_fields_in_show_view
  [:field_1, :field_2, ..., :field_n]
end

it 'display fields' do
  user_fields_in_show_view.each do |field|
    User.any_instance.should_receive(field).at_least(1).and_call_original
  end

  render
end

这很有效。

-

但完全相同的技术在“形式”部分中不起作用,使用相同的代码

def user_fields_in_form_view # List of fields need to be different, because of the associations
  [:field_1_id, :field_2, ..., :field_n]
end

it 'display fields' do
  user_fields_in_form_view.each do |field|
    User.any_instance.should_receive(field).at_least(1).and_call_original
  end

  render
end

它像这样抱怨:

Failure/Error: Unable to find matching line from backtrace
Exactly one instance should have received the following message(s) but didn't: field1_id, field_2, ..., field_n
# Backtrace is long and shows only rspec/mock, rspec/core, rspec/rails/adapters, and spork files

到目前为止我尝试了什么

1 - 我将测试的存根部分注释掉并输出rendered到控制台,手动检查我的视图生成了什么,是的,字段是否正确生成。< / p>

2 - 我用我分配给视图的模型替换了User.any_instance,错误略有不同,但仍无法正常工作

it 'display fields' do
  user = create :user
  assign :user, user

  user_fields_in_form_view.each do |field|
    user.should_receive(field).at_least(1).and_call_original
  end

  render
end

给出:

 Failure/Error: user.should_receive(field).at_least(1).and_call_original
   (#<User:0x0000000506e3e8>).field_1_id(any args)
       expected: at least 1 time with any arguments
       received: 0 times with any arguments

3 - 我更改了代码,因此it位于循环内部,如下所示:

user_fields_in_form_view.each do |field|
  it 'display fields' do
    user = create :user
    assign :user, user

    user.should_receive(field).at_least(1).and_call_original

    render
  end
end

与上述结果相同

我没有选择。我怀疑FormBuilder的内部对我起了不好的伎俩,但我无法弄明白,我对这些并不是很了解。感谢您的阅读

2 个答案:

答案 0 :(得分:2)

我经常尝试尽可能简单地编写单元测试。单元测试中的循环不会增加很多可读性,并且通常不是很好的练习。我会像这样重写测试:

it 'should display user name and email' do
  # note: `build` is used here instead of `create`
  assign :user, build(:user, first_name: 'John', last_name: 'Doe', email: 'jd@example.com')

  render

  rendered.should have_content 'John'
  rendered.should have_content 'Doe'
  rendered.should have_content 'jd@example.com'
end

因此,我们并没有限制它应该如何呈现名字和姓氏的观点。例如,如果我们的视图使用以下(坏)代码来呈现用户的全名,那么您的测试将失败,但我的测试将正常工作,因为它测试视图的行为,而不是其内部:

<%= user.attributes.values_at('first_name', 'middle_name').compact.join(' ') %> 

此外,一次测试中的多个断言也是一种难闻的气味。更进一步,我将用三个较小的测试替换这个测试:

it "should display user's first name" do
  assign :user, build(:user, first_name: 'John')
  render
  expect(rendered).to include 'John'
end

it "should display user's last name" do
  assign :user, build(:user, last_name: 'Doe')
  render
  expect(rendered).to include 'Doe'
end

it "should display user's email" do
  assign :user, build(:user, email: 'jd@example.com')
  render
  expect(rendered).to include 'jd@example.com'
end

======

UPD :让我们更加动态,以避免大量重复。 Tis没有回答为什么你的规范失败,但希望代表工作测试:

%i(first_name last_name email).each do |field|
  it "should display user's #{field}" do
    user = build(:user)
    assign :user, user
    render
    expect(rendered).to include user.public_send(field)
  end
end

为了使这些测试更可靠,请确保用户工厂不包含重复数据。

答案 1 :(得分:1)

我不太确定如何构建表单,但如果您使用form_forsimple_form_forformtastic_form_for帮助程序,实际上您使用的是其他对象。你写的东西(假设基本的form_for

= form_for @user do |f|

并且所有方法都被转发到对象f。现在f.object将指向@user,但它本身就是@user@user的副本,我不知道。所以我希望User.any_instance能够发挥作用。

无论如何,在进行视图测试时,如何设置字段内容并不重要,正确设置字段内容非常重要。假设您自己构建表单,切换到另一个库来构建表单,并且所有测试都会中断,因为它会以不同方式检索数据。这应该不重要。

所以我使用@DNNX,在您的视图测试中,您应该测试呈现的HTML的内容,而不是如何检索数据。