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

Popular posts from this blog

javascript - Laravel datatable invalid JSON response -

java - Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; -

sql server 2008 - My Sql Code Get An Error Of Msg 245, Level 16, State 1, Line 1 Conversion failed when converting the varchar value '8:45 AM' to data type int -