Better Tests Through Metaprogramming

Duplication causes all of the same maintainability issues in test suites it does in production code, but I often see the DRY principle violated in the name of comprehensive test coverage and fidelity.

Let’s say we have a Rectangle class that normalizes a range of inputs and we want to test all of them. How can we accomplish this without:

  • Writing an individual test for each input (duplication)?
  • Writing one test with multiple assertions (lost fidelity)?

Consider this approach:

1
2
3
4
5
6
7
8
9
subject {Rectangle}
formats = {comma_delimited_string: '100, 100, 500, 500',
           array_with_strings: ["100", "100", "500", "500"],
           array_with_ints: [100, 100, 500, 500]}
formats.each do |(format_name, data)|
  it "accepts and normalizes data passed in as a #{format_name}" do
    subject.create(data).coordinates.should == formats[:array_with_ints
  end
end

String interpolation in the test description provides nearly the fidelity of breaking out assertions into individual tests. Neat!