[cucumber] Cucumber and Chronic


#1

This may have been discussed before but just wanted to pass along a
killer one-two punch that we stumbled upon as an excellent and natural
extension to our domain language around the expression and testing of
complex time based constructs.

Please consider:

Cucumber allows you to specify behavior in natural language.

Chronic is a natural language date/time parser written in pure Ruby.
(http://chronic.rubyforge.org/)

Example of a cucumber test:

Scenario: Test control operations
Given that I have have a control operation named “set clock date time”
to “Monday Jan 1, 2009 10:00”
When the control named “set clock date time” runs
Then the clock should be “10:00”

Now, this works fine, if you’re only testing that you can set the
clock to “Monday Jan 1, 2009 10:00”. It gets more complex quickly when
you try to do much more than this. Adding chronic to the mix allows us
to define and use more complex time concepts in plain language. This
allows for the parsing of sentence fragments such as “next month” and
“next Tuesday” and combine them in to complex structures such as “next
Tuesday at 9:00” in a way that our tests continue to run as time
marches on.

For example:

sentence = “next tuesday at 3:00 pm”
=> “next tuesday at 3:00 pm”

time = Chronic.parse(sentence)
=> Tue Mar 03 15:00:00 -0700 2009

Now, the scenario can use this easily express clearly “when” the
control operation runs in more complex and useful expressions, for
example:

Scenario: Test control operations
Given that I have have a control operation named “set clock date time”
to “next tuesday at 3:00 pm”
When the control named “set clock date time” runs
Then the clock should be “next tuesday at 3:00 pm"

Scenario: Test spy sweeping schedules
Given that I have have a control operation named “clean spies” that
is scheduled to run “next Monday at 8:00 AM"
And the customer has excluded “weekdays” from allowing the control
operation “clean spies” to run
When the control named “set clock time” runs
Then it should log a message and quit


#2

On Sun, Mar 1, 2009 at 8:50 AM, Tim W. removed_email_address@domain.invalid wrote:

For example:

sentence = “next tuesday at 3:00 pm”
=> “next tuesday at 3:00 pm”

time = Chronic.parse(sentence)
=> Tue Mar 03 15:00:00 -0700 2009

Just be careful when when basing durations from “now” that daylight
savings time doesn’t affect anything.

///ark


#3

On Sun, Mar 1, 2009 at 11:07 AM, Mark W. removed_email_address@domain.invalid wrote:

Just be careful when when basing durations from “now” that daylight
savings time doesn’t affect anything.

Along the same lines, don’t write tests that assume 1.month.ago was <
29 days ago, or specs could start failing in March (as just happened
with us). :slight_smile:

///ark


#4

On Sun, Mar 1, 2009 at 6:30 PM, Mark W. removed_email_address@domain.invalid wrote:

On Sun, Mar 1, 2009 at 11:07 AM, Mark W. removed_email_address@domain.invalid wrote:

Just be careful when when basing durations from “now” that daylight
savings time doesn’t affect anything.

Along the same lines, don’t write tests that assume 1.month.ago was <
29 days ago, or specs could start failing in March (as just happened
with us). :slight_smile:

You wouldn’t happen to be on the Microsoft Zune development team,
would you? >8->

For date testing, I’ve just discovered and successfully used Notahat’s
“time_travel” plugin:
http://github.com/notahat/time_travel/

It’s essentially a scoped override for Time.now, so that any code you
pass it executes as if the current time is frozen at whatever you tell
it. This makes repeatable testing much, much simpler. This is the
same guy who developed Machinist (my preferred fixture/factory tool)
and not_a_mock, which I used for a little while before I abandoned
mocking. >8-> So…yeah. He does good stuff.


Have Fun,
Steve E. (removed_email_address@domain.invalid)
ESCAPE POD - The Science Fiction Podcast Magazine
http://www.escapepod.org


#5

On Sun, Mar 1, 2009 at 9:07 PM, Stephen E. removed_email_address@domain.invalid wrote:

For date testing, I’ve just discovered and successfully used Notahat’s
“time_travel” plugin:
http://github.com/notahat/time_travel/

We have just been stubbing Time.now, but I’ll think about time_travel.
One advantage would be not having to “manually” reset RSpec mocks
after each Cucumber scenario is run in After.

///ark


#6

Absolutely. I’d respectfully suggest that this is more a requirement
of the way the step definition or test fixture that implements the
feature needs to behave than the intent of describing time based logic
in a natural language such that product owners, ba’s etc. can write
them (i.e. Cucumber, FitNesse, etc). That Chronic takes into
consideration the things you mention (time zone, DST, Leap Years,
etc), is simply an imperative of it. Anyway, I think it fits
hand-in-glve with Cucumber and BDD in general. Just for the record, I
have no vested interest in Chronic and really don’t know who even
authored it, but I can say it’s looking pretty awesome in our own
Cucumber tests.

Thanks,

Tim


#7

On Sun, Mar 1, 2009 at 11:07 AM, Mark W. removed_email_address@domain.invalid wrote:

Just be careful when when basing durations from “now” that daylight
savings time doesn’t affect anything.

Like it did today, when two specs that used ‘Time.now.advance(:hours
=> 24).utc’ started failing.

///ark