Thursday, December 20, 2007

Testing Headaches

I was planning some additional posts before this one, but this really got on my nerves.

Rails really wants to make it easy for you to test your programs. It provides a whole framework for testing. That's great and commendable.

So, I finally took the plunge and started my project. I built some models, controllers and views using Rails 2.0's spiffy new RESTful scaffold generator, added user login management using the restful_authentication plugin (more on this in a later post), and tried running all the generated tests.

Errors, failures and what not, and I haven't written any of these tests, they were all generated by the generators!

The first problem was that all the functional tests should login before the test is run. OK, that makes sense, the generator couldn't know I was behind the authentication "wall". Fine, but the restful_authentication plugin's documentation is practically non-existent.
After searching around I found several forum posts that point to the login_as helper method. Just stick it in your setup method, they say, and you're home free:

def setup
login_as :quentin
end
the rest of the test should work as before (:quentin and :aaron are the automatically generated users, they apparently work for example.com).
However, no such thing happened.

After, endless trials and errors, detours and hacks, I tried adding login_as to each method and not through setup. Suddenly some of the tests passed without a problem. Those that didn't failed due to some other strange reason.
Now, remember, these are all auto-generated tests!

Anyway, it seemed there was some problems accessing a model with :id of 1. I checked the automatically generated fixtures, and, indeed, :id was not set! Didn't anyone test this Rails release?! This is the newest public release of Rails.

So, I added the :ids and lo and behold, most of the tests now passed.
I later discovered that one of the fixes done in Rails 2.0.2 were:
  • Fixed that functional tests generated for scaffolds should use fixture calls instead of hard-coded IDs
scroll down, it's the forth item from the end. Of course, this doesn't help me, since I scaffolded using ver. 2.0.1. Arghhhh!

By adding the mandatory record fields in the test_should_create_* tests, I got all the test to run properly. Being a rookie this also took me a while to figure out thanks to the "helpful" error messages.

What still bugged me was why I couldn't use the setup method. After some serious and associative digging I found this little post:
Rails 2.0 introduces a new (better) way to create your functional test cases. Instead of subclassing Test::Unit::TestCase directly, you can now subclass ActionController::TestCase, which will take care of the setting up the request/response environment for you.
...
And therein lies the gotcha: if you go ahead and create your own setup method not realizing that you’ve inherited one, you’ll clobber the one defined in the superclass. So, when you’re defining your own setup method, remember to call the original one using super...
so when I changed my setup method to look like this:
def setup
super
login_as :quentin
end
everything suddenly worked.

Now, it took Jeffrey Allan Hardy 15 minutes to figure this out and he wrote a book about Rails and is a partner at a boutique Rails consulting shop (whatever that means). It took me hours!
He updated his post to mention that this "gotcha" has been fixed on the Rails Trac (the Rails source repository) but that isn't much consolation nor use to me.

All my tests now pass and I'm going to sleep.

If you found this post helpful, please leave a message in the comments.
If you want to hear more about my mis-adventures with Rails, subscribe to the blog feed and you just might not have to go through it yourself.

5 comments:

Michal Hantl said...

Hello. I like your article:). I'm also testing my code and having hard time figuring whats wrong and whats going on.

jgervin said...

Hey, good article, but I am still having issues. I am using restful_authentication with 2.0.2 but still having issues with the before filter.

I have tried login_as :quentin but since quentin isn't an admininstrator then the testing fails.

Do you know how to create an administrator in the fixtures? I have tried role: administrator as a field in my user fixuters for quentin, but it then says database not found since "role" is another model/table and not an attribute of the users model/table.

A.S. said...

jgervin, I've not used roles, so I don't really know. I'm just a rookie (or Rails). I you find a solution, please write it up. It would be interesting.

Unknown said...

Does anyone know how to access the current_user object when doing functional tests?

Sam said...

Hey, thanks for the login_as tip.