Notes from Cleveland Ruby meeting on Thursday, Jan 25th

This post contains some python-related information, I promise.

Fun time. Corey Haines explained behavior-driven development and showed some examples using RSpec at last night’s Cleveland Ruby meetup.

As an aside, Corey said “powershell is what the unix command line will be when it grows up” and a thousand angels fell over dead when they heard this blasphemy.

The story-based tests in RSpec seem downright magic. You can write in an english-y syntax:

Given a = 1,
When
b.foo(a)
Then
b should return "Hurray"

Or something like that.

I like that RSpec supports a result called “Pending”. This guy writes a good explanation of how it works, and I agree with this remark:

It’s easy enough to rename a test method so it doesn’t execute, but before RSpec I’ve never worked with one where you can mark it as pending and it then reminds you that you still have work to come back too.

I figure that it would be straightforward to add this into nose. Maybe raise a special exception called PendingTest that gets caught differently.

I learned a neat way of using a mock object without having to pass it in as a parameter based on some code I saw last night.

Corey had a couponcontroller that operated on coupon objects. He made a mock coupon object to use with his tests for his couponcontroller. Then, in his test code, he monkeypatched the coupon module so that when somebody said “give me a coupon” he got a mock coupon instead.

I spent a few minutes trying something vaguely like that in python. I’m not sure I like it, but it gets the point across.

I have a file coupon.py:

# This is coupon.py.

class Coupon(object):
"I'm the real coupon"

def foo(self):
print "This is the real coupon"
return "foo"

And I have a file couponcontroller.py:

# This is couponcontroller.py.

from coupon import Coupon

def couponcontroller():
c = Coupon()
return c.foo()

In my test_couponcontroller.py, I want the couponcontroller to use my mock coupon, not the real one.

# This is test_couponcontroller.py.

import couponcontroller

class mockCoupon(object):
"I'm not the real coupon."
def foo(self):
print "Congratulations. You're using a mock."
return "foo"

def setup():
# Mess with the module.
couponcontroller.Coupon = mockCoupon

def test_couponcontroller():
"couponcontroller should return a string 'foo'"
assert couponcontroller.couponcontroller() == "foo"

It seems to work:

$ nosetests -s test_couponcontroller.py
couponcontroller should return a string 'foo' ... Congratulations. You're using a mock.
ok

----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

In summary, there’s clearly a lot of smart people in the ruby community, even if they insist on using syntax like

@adder ||= Adder.new

Published by

matt

My name is Matt Wilson and I live in Cleveland Heights, Ohio. I love random emails from strangers, so get in touch! matt@tplus1.com.

  • http://www.pirnat.com/ Mike Pirnat

    Take a look at Mocker and Mock — both have some facilities for making monkeypatches like that just for the duration of particular tests, which keeps things cleaner.

  • http://blog.extracheese.org/ Gary Bernhardt

    The Mock library Mike recommended is the same one I mentioned last night. I love it – it does everything I need and is only ~100 lines long.

  • http://www.coreyhaines.com Corey Haines

    Thanks for the kind words, Matt.

    I definitely use pending quite a bit. It is nice to have a facility to keep track of work that needs to be done that integrates with the testing tool. I haven’t thought about it before, but I might look into how to do add this sort of functionality to NUnit for my .net development.

  • http://www.couponsmate.com/coupons/tweet-adder-coupon-code tweet adder coupon code

     I think this meeting is excellent and everything is informative.  This is very essential and informative information for me. I would like to say your post is superb and relevant my topics.