100% test coverage! Catch all the bugs!
I’ve been working on a Ruby on Rails app for more than three years, and Ruby coverage for its rspec test suite has been at 100% for most of the last year. 😀
People with more experience may try to tell you this is a bad idea. Test what you need to test. 90% is a good rule of thumb. If you’re doing TDD right, you’ll be testing based on needs, and coverage will take care of itself.
No! Do it!
Why?
- You’ll learn a lot about Rails, your gem dependencies, and your test tools.
- It’ll help you write better tests and more testable code.
- You will find bugs you didn’t know about!
- It’s fun! Getting those tricky bits tested is a good puzzle.
- Once you get there, it’s easy to maintain.
Okay, but how?
- Delete the code paths that you can’t test!
- Use method stubs liberally:
[ruby]
allow(something).to receive
allow_any_instance_of(Something).to receive
[/ruby] - Test for expected errors to be raised:
[ruby]
expect { error_triggering_code }.to raise_error(/snippet of expected error message/)
[/ruby] - Stub or monkey patch controllers to raise the errors you want to test.
- Conditional modifiers and ternary operator are your friends. You can often hide two code paths in one line without making it harder to understand. If it’s good enough for simplecov, it should be good enough for you.
- Have code that only runs in development environment that is throwing off your coverage numbers? No problem!
[ruby]
allow(Rails).to receive(:env).and_return(‘development’)
[/ruby]
Lies!
You may have heard people say that code coverage is a lie. It’s true. For example, there are some tricksy ways to add specs for rake tasks to your test suite, but because rake tasks start from a different environment, they don’t integrate cleanly with simplecov. That’s why we exclude rake tasks from the coverage metrics in my app, even though we do test them.
Sadly, even once you reach 💯, it may be tough to keep it in the long run. Ruby 2.5 introduced a big change in the code coverage API. With that change, it has become possible for code coverage tools to report Branch Coverage rather than just line coverage, so the tricks with conditional modifiers and ternary operator may still not get you to 100% in the future. (The deep-cover gem also does this, without requiring Ruby 2.5.) But don’t fret; you’ll probably be able to do something like pin your coverage gem to the last version that just uses line coverage. A small price to pay for the peace of mind of knowing your app is 100% bug free.†Or maybe it’s just a number to brag about. Either way, worth it!
†Obviously this is not the case. But I still recommend trying to get to 100% coverage, for the reasons listed above.