Hey guys! The time has come. I want to share with you my reflections and thougths about testing in a Rails applications. Needles to say that strong inspiration came from David Heinmeier Hansson’s keynote at this year’s RailsConf. This presentation, my observations and experience are the main reason behind this post.
Wow! Am I able to write tests?
First of all I want you to know that some conclusions and statements are my own private opinions and you have the total right to disagree with them and all feedback is appreciated.
First a little bit of my rails history. When I first saw the Rails framework it was actually the first time I encountered automated application testing. I was a second year student and so far noone even mentioned anything about testing apps. Testing, in our mind, was manually ‘clicking through’ the application, checking the edge values, try to break the application. So imagine my excitment when I read that there is a way to write automated tests. I was like: ‘great so I can save the time of clicking through the app myself by configuring it to do it for me’.
The second big thing I discovered was that there are different types of tests in rails. You can tests models, controllers and views separetely. Great. So not only can I write automatic tests, I can keep them clean by testing only one piece of MVC architecture at a time!
But there was more. I learned about agile development. It contained so much insctructions and advices of how to write better software. I thought that this was the perfect guidebook for developer. By obeying these rules you ensure the quality of your product. Then I encountered the test driven development philosophy. And I totally agreed with it! TDD is about how you should implement new features of the applications. First you need to write the test, which of course will fail if you execute it, then you need to write the piece of code that makes the test ‘go green’. Finally, when you’ve got the working piece of code covered by the test, you can refactor it. It helps you focus only on the things that are really important for the client. I must admit that, at first, it was hard to write tests in the beggining. Especially when your user story is not as precise as you want. But later I got used to it. Combining all those things I was highly encouraged to write rails applications and tests.
And how it was in reality? The best way will be describing some real life examples from my work.
History 1 – abandon the TDD and integration.
Last year we started to develop a small rails application that was a typical startup. The clients knew more or less what they wanted, but we were prepared that the ideas and the overall shape of the application will change often. We have made the decision that we don’t want to use the TDD for this project, moreover we didn’t even write integration tests. So we just focused on basic model testing (methods, validations etc.) after implementing the feature. We finished the project in 3 months. Looking back, I must say that it was a good decision. I couldn’t imagine using TDD in this project. We started from a basic rails app to end up with angular + rails application. And if we would have started with integration tests from the begining we would probablly need much more time. I don’t even want to imagine rewriting those tests after changing the logic of the application again and again (not mentioning the refactoring). By skipping integration testing, we saved a lot of time, and we could focus on experimenting with adding/deleting features from the app rather than having good test coverage. Is it the univeresal way for all projects? Surely not.
History 2 – no tests means you are doomed.
A couple of months ago we helped a client who had a rails project done by some other company. He came to us to fix some things and add two or three additional features. He said that the app is 90% ready so our job will be only to cover the last 10%. There was a trick however. The application had literally not a single line of test code (except couple pendings generated by the scaffold generator ;) ). When we started to implement our fixes and add new features we ended up with the entire application bugged. I didn’t mention that this app had very poor code quality (I could write an entire post about some ‘solutions’ implemented there). Every change required one person to click through the app and report found mistakes. So here’s the decision – do we write tests now? Or we try to work with what we got? Based on conversation with the client we decided to work without tests (writing tests from scratch could be a money-eater). Was it a good decision? Honestly, the time we spent fixing bugs, refactoring methods and changing the flow was enough to rewrite the app from scratch.
History 3 – continous integration and rcov.
Lastly, we started to use Jenkins as a continous integration service. After each master push, tests are being executed and we got the info about code coverage of our app. At first we just wanted to have 95 – 99 % test coverage on each app. But what for? Is it really needed? What is the profit for us to have high code coverage? In my opinion 40% of tests should cover a success path and the rest 60% should contain all edge cases that could potentially cause an error in your application. So while writing the test you should answer a question “how can I possibly make this test go red?”.
Those three histories above describe different ‘testing rails’ philosophy. Which of them is the best? Honestly, I don’t think that there is a solution that we should stick with. I think the best way to writing tests is to use your smarts. You can’t just blindly follow all the rules but you need to think hard before you break them. Personally I like to think that tests should help us with maintaing the application and should grant us easier ways to develop the application in the future. So don’t try to test all the stuff. Try to test only what’s important and do this wisely.