I have just released DoubleAgents, a library for creating “test doubles” in Visualworks Smalltalk.

As I mentioned before, I’ve long felt that the use of a lot of mock objects and other test doubles was a sign of a design smell, but after reading Growing Object-Oriented Software, Guided By Tests by Steve Freeman and Nat Pryce, and Practical Object-Oriented Design in Ruby: An Agile Primer by Sandi Metz, I started to rethink my position.

As I’ve experimented with test doubles in recent months, I’ve found that they’re having a positive impact on my code and its design. I continue to be surprised by this.

In our code at work, we’ve been using some home-grown mocking and stubbing tools built on top of SmallMock and MethodWrappers. They work, but I found many of the tests too verbose for my liking, and the mix of tools didn’t offer a consistent API. I decided to take a new approach, and DoubleAgents is the result.

I won’t echo the documentation in this post, but here’s the initial example from my earlier post rewritten to use DoubleAgents:

DoubleAgents Example
Smalltalk.Hardware defineClass: #RegisterPairTest
superclass: #{DoubleAgents.DoubleAgentTestCase}
indexedType: #none
private: false
instanceVariableNames: 'controlRegister statusRegister pair'
classInstanceVariableNames: ''
imports: ''
category: ''
setUp
super setUp.
statusRegister := StatusRegister doubleAgent.
controlRegister := ControlRegister doubleAgent.
pair := RegisterPair control: controlRegister status: statusRegister
requestsWithSameResponse
<test>
statusRegister stub: #value return: 42.
controlRegister expect: #value: with: 42.
pair request: 42
requestsWithDifferentResponse
<test>
statusRegister stub: #value return: 24.
controlRegister expect: #value: with: 42.
pair request: 42 expecting: 24
waitsForStatusRegisterToChange
<test>
statuses := #(0 42) readStream.
statusRegister stub: #value do: [statuses next].
controlRegister expect: #value: with: 42.
pair request: 42
timesOutIfStatusRegisterDoesntRespond
<test>
statusRegister stub: #value return: 0.
controlRegister expect: #value: with: 42.
pair timeout: 1 milliseconds.
self should: [pair request: 42 expecting: 24] raise: RegisterTimeout
reportsStatus
<test>
statusRegister stub: #value return: 24.
self assert: pair status = 24

DoubleAgents’ primary home is the Cincom Public Store Repository. Check there for the latest version. I’ve also put a snapshot of the current version of DoubleAgents on GitHub. The Readme file on GitHub includes documentation of the API of DoubleAgents if you’d like more information before diving in. I’ve also submitted it for inclusion as a contributed package in the forthcoming Visualworks 7.10 release.

DoubleAgents was developed in VW 7.9.1, but is intended to be compatible with VW 7.7 and later.

DoubleAgents is licensed under the MIT license.