Taming Chaotic Specs: RSpec Design Patterns

Adam Cuppy

Abstract

Don’t you hate when testing takes 3x as long because your specs are hard to understand? Following a few simple patterns, you can easily take a bloated spec and make it DRY and simple to extend. We will take a bloated sample spec and refactor it to something manageable, readable and conci

Description

Don’t you hate when testing takes 3x as long because your specs are hard to understand? Or when testing conditional permutation leads to a ton of duplication? Following a few simple patterns, you can easily take a bloated spec and make it readable, DRY and simple to extend. We will take a bloated sample spec and refactor it to something manageable, read

Notes

This presentation is meant to be a live coding workshop and an in-depth review of test architecture. More often then not, specs become unwieldy and bloated because we forget that RSpec is still Ruby code and should follow a pattern. Starting with a small Ruby (Rails) project with a handful of RSpec tests, we will review the User model and it’s related unit test. This refactor kata will hit on:

Three primary design patterns:

Minimum Valid Object

Start testing from a verifiably valid state; therefore, every mutation of the object is planned and tied to the failure (if there is one).

Permutation Tables

Using multi-dimensionally areas to visualize the data being tested; making it much simpler to track variations and mutations

Golden Master

Snapshot a string representation of an object to file for later comparison. This works well when there is a lack of existing test coverage and the complexity of the application makes it hard to assert that the state of an object is accurate (green) in the beginning.

Bonus material

Best Practices

Briefly I review a few practices that help keep the tests functioning well:

  • Using describe titles like #instance_method and .class_method to maintain readability
  • Using contexts to define conditional situations
  • Using let over @instance vars
  • Using shared_examples to DRY up common expectations sets
  • Single assertion principle and when to break it
  • Isolating mixins to their own spec to avoid object dependency collision

I’ve given this talk as both a workshop at RailsConf and for RailsRemoteConf

Edit proposal