Quite some time ago, I came across a thread on a Ruby on Rails forum. It was a junior developer asking for general advice on app testing. So I asked myself: what would I want to know about writing tests if I was a novice? Here I made a list of 5 rules on application testing I think all developers should be using.
Rule 1: Writing tests before or after writing code? Doesn’t matter!
There are two possible tactics when it comes to writing tests. You may start with tests before writing code to avoid copy-pasting in the console, or write proof of concept first and then test it through. What’s more important is to run them on things that you suspect to break or change in the future, because tests are written for confidence that your application is working and for making future refactoring easier. Refactoring is crucial because you should be aware that apps won’t stay in their initial state forever. Your skills improve, tools change, design patterns evolve and tests allow you to adapt code faster.
Rule 2: Rule of thumb - pick the right test type for the right feature
Test things mostly end-to-end (aka integration tests) in a happy path, but for tricky mechanics add unit tests for every edge case. For end-to-end testing, it doesn’t matter what tool you will use, whether Capybara, VCR cassettes with recorded requests or actual requests to a database. What is important is to test on real data examples and the code that does something.
Unit testing with stubs and mocks is a great tool to verify the behavior of specific small parts in your application (units). But it doesn’t fit every part of any app, and writing such tests for every method and class is an easy way to make your app more rigid or petrify it to the extent you won’t be able to change anything.
Rule 3: Don’t petrify your application with tests
Because then you won’t be able to change it. It’s very easy to make an app too rigid with unit tests for every class and method - as a result, they give you false sense of safety. You have 100% code coverage but changing anything requires modifying multiple unrelated places to make tests pass. It’s very common for people new to TDD, because they get lured by the ability to write new specs. Do not write tests for every class, method and arguments configuration, because it not only wastes your time (in most cases) but also distracts you from refactoring and adapting your software to new requirements. Write enough specs to check all the important places in code but not more.
Rule 4: Don’t be afraid of removing dead code
Especially dead or trivial test cases. When you spot a test which looks like it doesn’t do anything important – just remove it. No mercy. Tests are there to show you when something goes wrong with your code. Removing excessive code will pay you off in faster test runs, giving faster feedback when you mess something.
Rule 5: Fix broken windows
There is a so called theory of broken windows, developed in criminology, but also used in software development.
Imagine two houses. One of them is ugly with all windows broken, the other one looks neat and inviting. The core idea is that everything started with just a single broken window. Don’t let your tests erode:
- Fix every flickering example, each failing spec as soon as you have time for it,
- Make sure your team knows about this policy,
- Run a continuous integration server which verifies every push to your code repository.
Sometimes it’s also nice to add some quality checking tools like RuboCop or Reek (developed by Chastell, our fellow developer at Rebased). They are better in spotting small inconsistencies and help making the codebase more consistent; reek also uses some AST analysis to give you clues which parts can be improved.
I hope those five simple and pragmatic rules will help you build your apps faster, with better confidence, and deliver. If there’s any tip you would like to add to this list or share your opinion about my tips - feel free to comment.