Fast, Sexy, and Svelte: Our Kind of Rails Testing

Dan Manges (ThoughtWorks) zak (unemployed)

a translation without buzzwords

short build times maintainable comprehensive coverage this talk: how to achieve these three things

what this talk is not about

selling you on tests if you haven’t bought into the value of testing, prepare to be very bored…

the testing spectrum
unit functional integration denial acceptance

what’s a unit test?

  fine

grained   focused on one object   provides the most accurate feedback   fails fastest   only one object / method under test per test method

avoiding unit test brittleness

gem install unit_record

not hitting a database is fast

let’s look at a super simple test

we could write a fixture

fixtureless unit tests

  focused

tests don’t require a dataset   fixtures are less clear

unit tests are for any class

unit tests for controllers

  reduce

dependency on models

  mock or stub models   stub view rendering (UnitController)   don’t hit the database (UnitRecord)   don’t depend on model validations

gem install unit_controller

unit testing views


  don’t


  laborious   really brittle

  views

aren’t objects   move view logic to presenters or helpers

unit tests the old & new way
unit tests are for models unit tests are for any class use fixtures for data focused tests don’t need fixtures hit the database disconnected from the database

what’s a functional test?

  coarser

grained than unit tests   involves more than one object   involves several methods   fails at an interaction level

functional tests require data

problems with fixtures

  polluted

sharing   laborious to create and maintain   creating associations   setting attributes your test doesn’t care about   doesn’t run validations

model factory

  factory

method pattern   creating data dynamically instead of statically in files   no sharing pollution   runs validations

getting a good factory

  build

it yourself   provide reasonable defaults   fill in associations

creating a factory

functional tests are also for any class

  interactions

between models   interesting database interactions   interactions between controller and model   interactions between controller and view*

interesting database interactions

interaction between controller and view*

  why

the asterisk?   don’t test the content of the view*   test that it renders successfully   we’ll test its content in acceptance tests

functional testing speed

functional tests in serial
real time: 9 min 42.951 sec

rake task for serial tests


deepTest for RSpec

Functional Tests in Parallel
  real

time: 6 min 30.441 sec   33% faster

DeepTest & The Database

functional tests distributed
real time: 2 min 2.522 sec 5 times faster than serial

gem install deep_test

functional tests the old & new way
fixtures for data factory for data functional tests are for controllers functional tests are for any class tests are run in serial tests are run in parallel

what about integration tests?

traditional integration tests

Integration Tests the New Way
  sometimes

useful for special purpose

  performance tests   smoke tests   tests simulating multiple users

  acceptance

tests are better for this level of granularity

what’s an acceptance test?

Selenium RC

writing acceptance tests

encapsulating a page

hide low-level details of page structure

data access

  direct

database access   use the same factory as functional tests   datasets
  difficult to maintain   make tests less clear   difficult to isolate test failures

focused acceptance tests

  hack

the session

  skip the login page   skip to part way through a wizard

acceptance test parallelization

  Selenium   DeepTest   web


& database cluster

test parallelization in general

hey it's Rails. it scales with hardware. and so do the tests

The End
  Dan’s

Blog:   Something Nimble:   Tools:
  deep test   selenium grid   unit record   unit controller