Mock Commands, Stub Queries
Posted by James Mead Fri, 03 Aug 2007 10:10:00 GMT
Zach Moazeni has just posted a suggested patch for Mocha over on his blog. My understanding of the patch is that it means expectations are verified even when an assertion error occurs in the test. Here is his example…
class Car
def initialize(parts = [])
@parts = parts
end
def start
started = true
@parts.each do | part |
# commenting out for failure
# started = started && part.start
end
started
end
end
class SomeTest < Test::Unit::TestCase
def test_start
engine_mock = mock("engine_mock")
car = Car.new([engine_mock])
engine_mock.expects(:start).returns(false)
assert !car.start
end
end
I’ve had a friendly & useful conversation with Zach about it, but I’m not convinced this is the right way to go. Using the one assertion per test school of thought, you can achieve the same goal by splitting the test into two so you get a test failure for the expectation and another for the assertion…
class SomeTest < Test::Unit::TestCase
def test_should_start_engine
engine = mock('engine')
car = Car.new([engine])
engine.expects(:start)
car.start
end
def test_should_start_if_engine_starts
engine = stub('engine')
car = Car.new([engine])
engine.stubs(:start).returns(false)
assert !car.start
end
end
Something that makes the example less suitable for mocking is that the Car#start method is both a command and a query. If you separate the two, testing with mocks might be easier…
class Car
def initialize(parts = [])
@parts = parts
end
def start
@parts.each { |part| part.start }
end
def started?
@parts.all? { |part| part.started? }
end
end
class SomeOtherTest < Test::Unit::TestCase
def test_should_start_engine
engine = mock('engine')
car = Car.new([engine])
engine.expects(:start)
car.start
end
def test_should_not_be_started_if_engine_is_started
engine = stub('engine')
car = Car.new([engine])
engine.stubs(:started?).returns(false)
assert !car.started?
end
end
I’d be interested to know what other people think…
One thing I do agree with Zach about is that submitting a suggested patch to an open source project is a great way of initiating a constructive conversation.
