Better array assertions using collect

October 27, 2008 Pivotal Labs

You could do this:

Person.tall_people.length.should == 3
Person.tall_people[0].should == people(:linda)
Person.tall_people[1].should == people(:dwane)
Person.tall_people[2].should == people(:rick)

This is better, because it’s clearer, and because in one stroke you prove bounds, content, and order:

Person.tall_people.should == [
  people(:linda),
  people(:dwane),
  people(:rick)
]

I argue that this is best:

Person.tall_people.collect{|p|p.first_name}.should == [
  "Linda",
  "Dwane",
  "Rick"
]

Failures messages are a pleasure to read

  expected: ["Linda", "Dwane", "Rick"],
  got: ["Juliette", "Jeanne"] (using ==)

And code is clearer overall (the price is a “collect”)

Collecting away from the original object (and into primitives) is not only clearer, in most cases your aim is not to re-prove that the element objects are fully and properly configured. You’ve already done that elsewhere. You only want to prove, in the simplest possible terms, that the group of things you got is what you expected to get.

Let’s say you don’t intend to care about order. Sorting on primitives is a snap:

Person.tall_people.collect{|p|p.first_name}.sort.should == [
  "Dwane",
  "Linda",
  "Rick"
]

Slightly more controversial:

Person.short_people.collect{|p|p.first_name}.should == []

The collect seems silly at first glance, but you’re making present and future assertion failures much friendlier. You’ll be happy about brain cycles saved and sanity kept during big refactorings.

About the Author

Biography

Previous
Fire Eagle
Fire Eagle

Seth Fitzsimmons and Blaine Cook talk about Fire Eagle, a location-awareness provider for online applicatio...

Next
Testing modules that get included in a controller
Testing modules that get included in a controller

We recently ran into a problem of testing a module that was getting included in multiple controllers. More ...