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.
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…