Quantified Awesome: Development-driven behaviour and integrated tests for life

2011-12-14: Updated step code

In terms of testing code, behaviour-driven development is fantastic. You can write your tests in pretty much plain English using a testing tool like Cucumber for Rails, which makes it easier to communicate with other people (including clients!). There’s a certain satisfaction in getting your tests to pass, and when they break, you know something needs fixing.

I’ve been thinking about what automated tests might look like in life. It turned out to be easy to prototype, thanks to the data I’m already collecting. It’s almost like development-driven behavior: can I apply the tools I use in software development to help me change my behaviours in life?

Here are some results from my very first integration test of real life:

Feature: Development-driven behaviour

  Scenario: Check for overdue books                # features/life.feature:2
    When I check our library items                 # features/step_definitions/life.rb:3
    Then there should be no items that are overdue # features/step_definitions/life.rb:7

  Scenario: Check my work load                       # features/life.feature:5
    When I look at my time use for the past 7 days   # features/step_definitions/life.rb:11
    Then I should have time data                     # features/step_definitions/life.rb:19
    And I should have worked between 40 and 44 hours # features/step_definitions/life.rb:24
      <46.5166666666667> expected to be
      <=
      <44.0>. (Test::Unit::AssertionFailedError)
      ./features/step_definitions/life.rb:26:in `/^I should have worked between (\d+) and (\d+) hours$/'
      features/life.feature:8:in `And I should have worked between 40 and 44 hours'

  Scenario: Check if I'm sleeping                        # features/life.feature:9
    When I look at my time use for the past 7 days       # features/step_definitions/life.rb:11
    Then I should have slept between 8 and 9 hours a day # features/step_definitions/life.rb:29

Failing Scenarios:
cucumber features/life.feature:5 # Scenario: Check my work load

3 scenarios (1 failed, 2 passed)
7 steps (1 failed, 6 passed)
0m0.833s

Cucumber highlights failing tests in red and it lists the failures as well.

Here’s the steps.rb that I’ve started fleshing out:


When /^I look at my time use for the past (\d+) days?$/ do |arg1|
  @start_time = (Date.today - arg1.to_i.days).midnight.in_time_zone
  @end_time = Date.today.midnight.in_time_zone
  @log = TimeTrackerLog.new(User.first)
  @entries = @log.entries(@start_time, @end_time)
  @summary = @log.summarize(@start_time, @end_time)
end

Then /^I should have time data$/ do
  assert @entries != nil
  assert @entries.size > 0
end

Then /^I should have worked between (\d+) and (\d+) hours$/ do |min, max|
  assert_operator @summary['A - Work'] / 1.hour, :>=, min.to_f
  assert_operator @summary['A - Work'] / 1.hour, :< =, max.to_f
end

Then /^I should have slept between (\d+) and (\d+) hours a day$/ do |min, max|
  average = @summary['A - Sleep'] * 1.0 / (1.hour * ((@end_time - @start_time) / 1.day))
  assert_operator average, :>=, min.to_f
  assert_operator average, :< =, max.to_f
end

# LIBRARY

When /^I check our library items$/ do
  nil # Actually stored in database, so we don't need anything here. This is more for semantics
end

Then /^there should be no items that are overdue$/ do
  assert_equal 0, LibraryItem.where('status = ? AND due < ?', 'due', Date.today).size
end

I am pleasantly boggled that this is possible, and will probably write all sorts of odd tests now. Because Cucumber can fill in web forms, click on stuff, and so on, I might even be able to use it to check information on other sites. (When I check my mail, then all the messages in my inbox should be less than a week old?)

Oh, the possibilities…