
Ask Mr. Lizard, from Jim Henson’s Dinosaurs
It’s time to play “Ask A Tester Person”, where I answer questions that I’ve gotten via email or otherwise about Rails Testing topics.
If you have a question for Ask A Tester Person, send it to railsprescriptions at gmail.com.
I’ve got two questions today:
Question 1: I’m writing too many tests!
One subject I still have questions
about is how to test authorization in controller tests. In my
applications I’ve been testing three different user cases for every
controller action, but this leads to, for example:test_edit_by_anonymous_user test_edit_by_unauthorized_user test_edit_by_authorized_userSo every action has at least three tests, which obviously means a
*ton* of tests for the entire application. This has always felt like
overdoing it but I haven’t yet been able to convince myself that just
testing the authorization part of the code is sufficient. If I could
isolate the authorization mechanism for testing that might convince
me, but I’m not really able to do that (maybe my authorization process
needs to be redesigned?), and I’m not sure I’d be convinced
anyway…how the application responds in all three cases seems like
something that *should* be tested for every action…
I doubt that your authorization process needs to be redesigned, but then I’ve never seen your authentication process.
I’d recommend a couple of different things to clean this up a bit. On the assumption that unauthorized access has largely the same behavior across the application, you can create a boilerplate test like this example — the example uses Shoulda, but the basic idea should work in any framework.
self.def should_block_access_for_anonymous_user(*actions)
actions.each do |action|
should "block anonymous access for #{action}" do
logout_current_user
get action
assert_redirected_to root_path
end
end
end
Which you would then use as:
should_block_access_for_anonymous_user :edit, :update, :delete
The implementation shown here is probably a little too simplistic for full use (you might need to pass more information than just the action for each request), but the simple version could easily cover the most basic authentication issues with very little fuss.
If your authentication system is more complicated, the other option is nested contexts — again, this is in Shoulda, but can be adapted to RSpec or the Context gem:
context "GET edit" do
setup do
# generic edit setup here
end
context "with an anonymous user" do
setup do
logout
get edit
end
should "not allow access" do
assert_redirected_to root_path
end
end
context "with an admin user" do
setup do
login_as_admin
get edit
end
should "allow access" do
assert_response :success
end
end
end
The upside of this compared with what you are probably doing is that it consolidate the setup between the different options. The downside is that it can be kind of verbose and hard to follow. But it’s still potentially easier than writing three separate tests for each action.
Question two: I’m creating too many objects!
Okay, I actually can’t find the email that this came from, which is driving me crazy, because how do you lose an email message these days? Anyway, the gist was that this person’s tests were running very slowly because he or she was creating so many objects for each test — I distinctly remember the number 50 to 100 being tossed around. So the question was how to avoid creating so many objects?
The bottom line is that there’s no way that you should need to create 50 to 100 objects for every TDD test, or even for any TDD test — it’s pretty rare that a unit-level test really needs that much data to work. There are a lot of potential issues here. Three that spring to mind are:
- You are trying to test too much code at one time. It’s possible (though still not very likely) that an integration test might need that many objects, but testing a single method almost never does
- You’ve transitioned from fixtures to factories, but you are still writing your tests as though you were using fixtures.
- You have perhaps an unnecessary fixation on providing “realistic” data in unit tests.
There’s some overlap here. One cause of this is problem is that in fixtureland, there’s very little marginal cost to creating new objects, so the tendency is to create fairly large aggregations of objects that cover all possibilities and have that be the universe for all the tests. When you transition to factories, though, keeping that big data blob around is not necessary. Since you can and should be custom-creating the data for each unit test, most model methods only need one model with specific attributes in order to specify the logic. Sometimes that model will need associated objects, but the factory tool can be set to create those automatically.
A special find method or named scope can be tested with as little as two objects — one to be found and one to be skipped. Sort logic similarly can be tested with two or maybe three objects. If the logic is really complicated, it’s better to do multiple tests with small amounts of data than one test with the whole shebang. The idea of a “unit” test is to verify one small piece of logic with as little data as possible, not to check program behavior under realistic data load — that’s what integration tests, performance tests, and actual user acceptance is for.
I feel like I’m answering the question “How do I create fewer objects in my tests?” with “By creating fewer objects in your tests”, I hope this answer gives you some tools for minimizing the number of objects you need to create in your tests.
Related Services: Ruby on Rails Development, Custom Software Development, Testing and Quality Assurance

You’ve got 2 “with an admin user” contexts in the last code block of question 1. The first should actually be “with an anonymous user”.
In question 2, you say “when you transition to fixtures”, but I think you mean transitioning to factories.
Thanks — corrected.
[...] Ask A Rails Tester Person | Pathfinder Software Development | Blogs [...]