Since my talk at Mountain West Ruby Conf I’ve been able to chat with a bunch of people about testing. A number of people had questions or wanted to debate details of the anti-patterns I listed. Others asked about anti-patterns that I had to cut for time. Over the next few months I’ll write a blog post about each anti-pattern so that I can go into more depth.
Anti-Pattern: Testing Other People’s Code
When I was learning Rails and TDD I wrote bad tests. Most people do this when they’re learning and a lot of people keep doing it after they’re past the novice phase. A classic example would be something like this:
class OrderTest < ActiveSupport::TestCase def test_find_order_by_id order = Order.create! o = Order.find(order.id) assert_equal order, o end end
A more experienced Rubyist reviewed that code and asked me, “What are you testing?”
I replied, “I’m testing that find returns the correct record.”
He responded, “ActiveRecord has tests for that. You don’t need to test it. Test what you provide”
It was a light-bulb moment for me. I’d been unclear about what I should be testing and what was too simple or otherwise wasn’t worth the effort.
Test What You Provide / Test The Code You Write
Your tests verify that your code is functioning correctly. Good tests verify the contract/api the software provides to users. Good tests also verify that all the code written is working correctly.
In practical terms this means you shouldn’t test things like ActiveRecord::Base#find, setting attributes, and save most of the time.
In typical cases you don’t have to write any code to enable this functionality and its already been tested in ActiveRecord.
You should have tests for things you write that extend the base functionality. Validations, associations, and any callbacks you write need at least enough tests to make sure you put the necessary code in the models.
When a library is untested
Another question I’ve heard a lot is “What if the library I’m using isn’t tested/doesn’t work/was written by very dumb gerbils?”
The flippant answer is “Find a better library.” In ruby land there always seems to be multiple libraries for a given task. Use something like Ruby Toolbox to find something that is tested properly.
When finding a better library isn’t an option I generally write my own tests against the library. I put them in a separate directory from our application tests (even a separate repo). I keep them separate because I want a clear line between “my/our code is broken” and “the library is broken”. I have them under different CI runs if possible.
If the library you are using is open source contribute the tests back to the project so someone else doesn’t have to do the same thing you just did. Leaving a project better than you found it is the nice thing to do.
If the library isn’t open source I still try to provide tests I write to the relevant developers. I’ve found having tests of the contract eliminates a lot of finger pointing when two parts of a system won’t talk to each other. They can also help debug changes in a large system by narrowing down where the bug might be.