12 Steps to Testing in Rails
We’ve several times complained about testing in rails. It’s difficult. It’s confusing. It’s time-consuming. No one really shows you how to do it well. There are too many choices for methods. You feel inadequate. Still, we soldier on. Or at least, in theory we soldiered on. In practice, our test code languished.
Until. A major refactoring was required on an app. Tried to convince client that feature requiring refactoring was not really that important. Oh, yes it is, says client. Okay, says I, and go in with a sledgehammer.
Well duh, I broke everything. I managed to implement the feature, and broke practically everything else in the process. And I couldn’t run my tests, which I’d been avoiding since long before the sledgehammer got involved, so they were in no shape to tell me what I’d broken anyway. And so Max just kept sending me Trac notifications from the other room, and I fell into despair when I realized that I had turned the code base into a steaming pile of putrid excrement. I don’t deserve to call myself a programmer, I thought. If only I had been diligently testing, this would never have happened.
So that was my ‘hit-bottom’ moment, when I realized that I had no control over my code and that I was ready to give my code over to the higher power of test-driven-development. I just had to figure out how to do it.
A lot of things were holding me back from making the transition to TDD. The biggest one, I discovered, was perfectionism and overwhelm. So many different ways to test. So many different things to test. So many different rails luminaries talking about their favored testing methods. So many different testing plugins, add-ons, and approaches. Too many decisions. I would sit down to write tests and just be absolutely paralyzed.
Once I realized that my big problem was perfectionism, I thought immediately of FlyLady. FlyLady is the reason our household is no longer buried in laundry and our kitchen is no longer buried in dirty dishes. FlyLady has some really great hacks for getting housework done, and those hacks can be applied to writing test code too.
Here are the most important points that Flylady makes:
- The goal is “progress, not perfection”.
- Baby steps will get you there.
- You can do anything for 15 minutes.
FlyLady counsels us to start with the tools we have on hand, not to try to do everything all at once, to put one habit in place before we start worrying about others. Most importantly, she constantly reminds us that housework done badly still, in her words, “blesses” your household. In the same way, testing done badly still blesses your application. Any testing is better than no testing. Ugly, non-DRY, simple, non-idiomatic, inefficient tests are still tests, and they’re getting you closer to where you want to be, testing-wise.
With these principles in mind, I’ve finally been making progress on developing the TDD habit. Here’s my very own 12-step program for testing in rails. I sincerely hope it helps other fledgling Rails TDD programmers, and I’ll keep everyone posted on my progress.
1) Admit that without tests, you have no real idea of what your code does. You have no control over your code.
2) Forgive yourself for all the untested code that you’ve written in the past.
3) Open up any one of the generated test files in any one of your rails projects, and write a test. Just one. Do not write fixtures. Do not decide you really need to be using RSpec instead and get distracted downloading and playing around with it. Do not spend a lot of time reading other peoples’ clever testing strategies. Don’t even think about mocks or stubs. Just write a test. Start with unit tests, they’re easiest.
4) When you’re done writing the test, applaud yourself.
5) Now open up the terminal, cd to your project dir, and type “rake test”.
6) When the test is done running, applaud yourself.
7) Now make the test pass.
8) Again, applause.
9) Do the whole thing again. And again. And again. Don’t do it for more than 15 minutes at a time. Set a timer, write 15 minutes of awful, non-idiomatic, stinky, not DRY, trivial test code, and when the timer rings, ‘rake test’ and give yourself a cookie.
I’m only at step 9. I think steps 10, 11, and 12 will be:
10) After a long time, testing will start to feel more natural. You can take a few minutes to fiddle with fixtures, if you want. You can branch out into assertions you haven’t used before. Go crazy with assert_select. No, now is not the time to check out rspec, rbehave, or cruisecontrol. Just keep writing tests.
11) By now, you’ve started to write your tests before writing your code. You don’t have to look up assertions. You’ve developed opinions about how to organize your test code, and you know what really bugs you about test code, what you wish it could do differently, what trips you up and slows you down. Now, and only now, are you ready to look into the various testing plugins, tools, and alternate testing theories.
12) You are now a testing master. Spread the TDD gospel far and wide.
From _A Guide to Testing the Rails_, a fantastic explanation of why we should write test code
As mentioned before, tests offer proof that you’ve done a good job. Your tests become your own personal QA assistant. If you code your tests correctly, at any point in development, you will know:
- what processes work
- what processes fail
- the effect of adding new pieces onto your application
With your tests as your safety net, you can do wild refactoring of your code and be able to tell what needs to be addressed simply by seeing which tests fail.
In addition to normal “did it pass?” testing, you can go the opposite route. You can explicitly try to break your application such as feeding it unexpected and crazy input, shutting down critical resources like a database to see what happens, and tampering with things such as session values just to see what happens. By testing your application where the weak points are, you can fix it before it ever becomes an issue.
A strong suite of tests ensures your application has a high level of quality. It’s worth the extra effort.
Another positive side-effect of writing tests is that you have basic usage documentation of how things work. Simply by looking at your testing code, you can see how you need to work with an object to make it do it’s thing.
The online book is a fantastic resource. Thank you, thank you, Sam-I-Am.
Testing Rails: the learning curve
Max and I are trying to learn how to write tests for our rails apps. Like many things in rails, testing seems intuitive to those who understand what’s going on already, but people who claim there’s no learning curve are deluded. The first three times I opened up my test directory and started trying to write test code, I grew incredibly frustrated and confused and gave up. “What’s assigns() do? How do I write my fixtures? Why do I always stick my colon in the wrong place when going back and forth between yaml and ruby code? What should I be testing anyway?”
“Who needs tests?” I thought. “That’s what QA is for! No one can figure this stuff out! I have no frackin’ clue what is going on here, and I never ever will.”
But I kept trying. When Max and I sat down this morning to write tests for our current project, we quickly grew, yes, frustrated and confused. We snapped at each other. Max squinted a lot, and I pointed accusingly at the screen a number of times. “See! See! Do you SEE what we are doing here?!” We couldn’t get one teeny tiny little test to pass. We wanted to do pretty much anything else.
But okay, we said. Learnd-ing is hard, as Ralph Wiggum (or a certain George) might remark. We are frustrated, but we will get it.
Eventually, we got our test to pass.
Now we just have about a zillion more tests to write, and we’ll be all set.
