Bit of a nitpick but I find myself testing attributes in my feature specs and am beginning to wonder if this is good practice?
For example, I may have a form object which updates multiple models and so I end up with abstracted methods in my capybara spec that look like:
def user_fills_in_form(form_attributes)
# fill_in ..., with: ...
end
def model_attributes_should_equal(args)
# expect(something.attribute).to eq args.fetch(:attribute_name)
end
def another_model_attributes_should_equal(args)
# expect(something.attribute).to eq args.fetch(:attribute_name)
end
Perhaps Iâm doing outside-in TDD wrong - as I think I end up with this situation when Iâm trying to test that everything is working correctly from my feature spec before dropping down into the form object unit test.
Is this really an issue - are you strict about this? Is this approach acceptable? Or should you strictly test attribute assignment in your unit tests?
If Iâm testing the attributes of a model, thatâs where I do it.
I prefer my integration tests to focus on what I can see in the UI. I rarely reach into the database from them.
If you want to confirm that submitting âJohn Smithâ in a form will later display âWelcome John Smith!â, thatâs fine. But I wouldnât check the DB to see if the name was set to âJohn Smithâ.
Thatâs what I do as well. Checking the database would be an implementation detail. Using something like expect(User.all.last.name).to eq 'bob' in feature tests is especially bad. You canât switch databases or ORMs without breaking the test. So if you need to check for attributes Iâd abstract it like you did, @ralphwintle.
I have a similar issue with feature tests when testing GET requests though: It seems to be common practice to create some database records (using factory_girl for example) first and then assert against some elements on the page. Isnât setting up the database records âreaching into the space capsuleâ[1] and therefore an implementation detail? We wouldnât do this kind of stuff when testing an array implementation[2]:
So, should we test our GET`` requests in a similar way? Should we test GETat all or just use it to verifyPOST`'s correct behavior? Hereâs an example [3]:
before do
post '/api/v1/posts', {title: 'Testing attributes with Capybara'}
end
it 'returns all created posts' do
get '/api/v1/posts'
expect(json_response['posts'].size).to eq 1
expect(json_response['posts'][0]['title']).to eq 'Testing attributes with Capybara'
end
This has the nice advantage of being pretty robust against any changes concerning the persistence layer. On the other hand this test will fail if either of the two implementations (GET or POST) donât work. Not much of an issue in my opinion.
I would love to her some opinions on that one.
[1] http://www.youtube.com/watch?v=URSWYvyc42M.
[2] Well, to be fair: Thereâs no easy way to reach into the MyArray object without relying on hacks.
[3] Using API specs instead of a webpage for simplicityâs sake.
So I think what actually happened was I was creating a pretty standard resource using outside-in development and got a passing spec (testing successful scenario only focused on the UI) without specifying any attributes in my strong parameters e.g.
def invoice_params
params.require(:invoice).permit(
# spec passed with this not filled out
)
end
To make sure I was getting the correct attributes set, I then wrote value expectations on my attributes in my feature spec.
Now that I think about it, the better approach would have been to create a bunch of specs around the validations (using Shoulda Matchers) and then create a factory with the minimum requirement to pass those validations so you can expect the object to be_valid. That way the form wonât result in the successful path unless the resource has the necessary attributes.
Attributes without validations would just get caught/tested in other feature specs where those attributes may appear in the UI.
Iâm guessing this is similar to howâd you do it?
Interestingly, asked a few people at work and got mixed answers (some did test attributes in feature specs and some didnât).
Interesting. So it seems like youâre asking if itâs OK to skip part of the setup phase in your integration test by using tools such as FactoryGirl or whether to implement all the steps required (i.e. exercising the post in a before block) so that you may test the expected outcome?
I donât see too much issue with the way youâve done it, although following the TB style guide of including the 4 phase test pattern (getting rid of the before block) and using a Factory may make it a bit more readable.
Iâm not quite sure what I had in mind made it across the internet.
So, to put it simply: Donât use factory_girl, ActiveRecord or any other stuff which interacts with the database in your integration [1] tests. It makes them brittle. If the user doesnât see a change[2] to your application your integration tests shouldnât need to be changed.
(Thatâs the extreme opinion. There might be exceptions where setup is actually required (e.g. your app might require some kind of Country data))
To come back to my MyArray analogy: You wouldnât set some instance variables within the class in the setup phase of your test, because this would obviously break if you change the implementation from using a tree to using a linked list.
[1] I mean the stuff which goes into the features folder in RSpec. Integration tests actually cover a much larger range of tests and are not restricted to UI interactions.
I donât know. It seems to me that setup may depend on a case by case basis i.e. whether you go for end to end testing including each step in your setup phase or having an integration spec that tests âsmallerâ groups of behavior, if that makes sense?
I guess if you were asking for opinions, I wouldnât be against using factory girl as part of my setup in a feature spec, providing it was called for⌠I wouldnât call it an extreme opinion either.
Perhaps not such a good example, but in the Clearance gem they have some rack middleware that lets you
visit root_path(as: user)
This is sort of hinting at what Iâm suggesting in that in some circumstances I think itâs OK to bypass some setup to get to where you want in order to test your UI.
Just my 2 cents. Interested to hear other peoples thoughts.
I regularly perform setup for integration specs using factory_girl and have been quite happy with the results.
I do agree it increases brittleness, but only slightly, and comes with a large win in terms of speed (you donât have to navigate 5 page loads to get the system set up) and test clarity (itâs sometimes much more obvious what youâre testing when you can set it up without clicking on a bunch of UI elements).