ruby on rails - Rspec2 + Rails4: Testing for displayed model fields in form partial -
question
i'd write tests check model fields displayed in "show" , "form" partials. succeeded "show", not "form".
main constrain: solution must able loop through array contains each names of model fields.
i believe case can interesting trying shorten test script files, while having many fields, , having complete control on what's displayed , what's not, i'll put efforts trying find solution, if please :)
form view
nothing fancy
= form_for @user |f| = f.select :field_1, options_from_collection_for_select ... = f.text_field :field_2 ...
actual situation
i found easy way "show" partial, here how spec file looks like:
def user_fields_in_show_view [:field_1, :field_2, ..., :field_n] end 'display fields' user_fields_in_show_view.each |field| user.any_instance.should_receive(field).at_least(1).and_call_original end render end
this works well.
-
but exact same technique not work in "form" partial, using same code
def user_fields_in_form_view # list of fields need different, because of associations [:field_1_id, :field_2, ..., :field_n] end 'display fields' user_fields_in_form_view.each |field| user.any_instance.should_receive(field).at_least(1).and_call_original end render end
it whines this:
failure/error: unable find matching line backtrace 1 instance should have received following message(s) didn't: field1_id, field_2, ..., field_n # backtrace long , shows rspec/mock, rspec/core, rspec/rails/adapters, , spork files
what tried far
1- commented out stub part of tests , output rendered
console, manually check what's generated view, , yes fields correctly generated.
2- replaced user.any_instance
model assign view, error different still not working
it 'display fields' user = create :user assign :user, user user_fields_in_form_view.each |field| user.should_receive(field).at_least(1).and_call_original end render end
gives:
failure/error: user.should_receive(field).at_least(1).and_call_original (#<user:0x0000000506e3e8>).field_1_id(any args) expected: @ least 1 time arguments received: 0 times arguments
3- change code it
inside loop, this:
user_fields_in_form_view.each |field| 'display fields' user = create :user assign :user, user user.should_receive(field).at_least(1).and_call_original render end end
same result above
and run out of options. suspect internals of formbuilder play bad trick on me can't figure out, i'm not knowledgeable yet. reading
i try write unit test simple possible. loops in unit tests don't add readability , not practice in general. i'd rewrite test this:
it 'should display user name , email' # note: `build` 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
thus, we're not limiting view in how should render first , last name. example, if our view uses following (bad) code in order render user's full name, test fail, test work fine, because tests behaviour of view, not internals:
<%= user.attributes.values_at('first_name', 'middle_name').compact.join(' ') %>
moreover, multiple assertions in 1 test bad smell too. going 1 step further, i'd replace test 3 smaller ones:
it "should display user's first name" assign :user, build(:user, first_name: 'john') render expect(rendered).to include 'john' end "should display user's last name" assign :user, build(:user, last_name: 'doe') render expect(rendered).to include 'doe' end "should display user's email" assign :user, build(:user, email: 'jd@example.com') render expect(rendered).to include 'jd@example.com' end
========
upd: let's make more dynamic in order avoid tons of repetition. tis doesn't answers why spec fails, represents working tests:
%i(first_name last_name email).each |field| "should display user's #{field}" user = build(:user) assign :user, user render expect(rendered).to include user.public_send(field) end end
in order make these tests more reliable, make sure user factory doesn't contain repetitive data.
Comments
Post a Comment