Accessing database in integration tests

@benorenstein this is from one of your great posts:

Verifying integration tests via database access

Fee: $20 Integration tests should verify through the UI. Don’t go
peeking in the database.

Is this a never do it rule, or you can do it when you have a good reason rule?

Some use cases:

  1. I had a bug in my application. Edit form has been creating new object instead of updating existing one. So I’ve added expect { click_button 'Edit Object' }.not_to change(Object, :count) to my integration tests. Because all other UI assertions were passing and I did not detect this bug in my tests.

  2. I need to save some data and show message to user. Something like Data has been saved. There is nothing else in UI what could be used for assertion that data has been saved. Only way which I see is to access database in test and assure that data has been saved.

So following your rule, what is the correct way to test my use cases without accessing DB?

Many thanks in advance for your answer!

Others: feel free to comment on this, too.

@patrikbona, for case 1, instead of checking in the db, I would check that the Edit action actually edits a property. Usually I would set up a object with FactoryGirl, have the test run through the edit process and setting an expectation that a property was changed.

For case 2, using Capybara, I would use the “has_content” method. That can check if you are displaying a notice or alert and verify the text.

Hope this helps :slight_smile:

Well it is exactly what I did, but it did not help. Property was changed because new object has been created and saved so all entered data were there. Only change which could user see is different url of edit page. Hmm, so maybe I can use this for assertion.

If I display just flash notice it doesn’t mean that data are really saved. It just means that I’ve set and displayed flash message…

I’m sorry, maybe I didn’t understand your question for case 1:

If in your test you setup object “X” with a specific property and have the test edit it, you’d know if your code is producing a new object instead of editing one. Otherwise the assertion I suggested would make the test fail.

As for case 2: it is a question of setting the message in a conditional, i.e. if the object is saved, set this message. Then you’d know that the data was saved, otherwise the message would not be set.

Again, if I am not understanding your questions, let me know :slight_smile:

Case 1:

I was thinking about this little bit.

After saving edit form I am redirected back to edit form. So if I am checking if there are values that I’ve entered then my test pass even if a new object is created because I see edited values (but for new object).

But I can add just one more step like visit edit_issue_path(issue) before assertions and then my test would fail if new issue has been created before because old one is still not updated.

So thanks for you answers, that is what I needed. Just to think little bit more when I wanted to reply to your suggestions ;).


btw. regarding case 2). I do not thinking that checking for flash message is enough. If I forget to add new attribute to list of permitted parameters, then it is not saved to the database. And are still passing.

But maybe I test too much… I don’t know.

Yes, that is something to take into account. But I believe that is something that should be picked up by the unit tests.
So i’d feel okay with the integration test or feature checking that the action is working from the UI.