[Esug-list] Fwd: Re: Proposal for Mock Objects at ESUG 2011

Frank Shearar frank.shearar at gmail.com
Fri May 27 17:34:21 EDT 2011


On 27 May 2011 21:56, Colin Putney <colin at wiresong.com> wrote:
> On Fri, May 27, 2011 at 12:42 PM, Frank Shearar <frank.shearar at gmail.com> wrote:
>> You miss the point of mocks. Mocks are there to allow you to test your
>> code quickly and cheaply against things that may not work in a quick
>> manner.
>
> Not likely. Hernán has been around the block and he speaks from long
> experience and deep thinking on software design. If you read his post
> a little more carefully, you'll see that he distinguishes between test
> doubles in general and mocks as a particular form of test double. He
> uses test doubles - you don't get 23,000 tests to run in 7 minutes
> without them. It's just *mocks* that are mostly unnecessary.

Hernan, I didn't mean to bite your head off. Next time I'll pause a bit longer.

> Personally, I find that mocks are *very* useful in a few very specific
> situations, but they can cause problems it other situations. They're
> like a very specialized tool - invaluable when you need it, but kept
> in the bottom of the toolbox and not used very often. Where I find
> them useful is in testing communication. For example, I'll use a
> MockWritestream to throw an exception if the code under test writes
> something unexpected into the stream. It's handy when testing code
> that writes out files in a particular format, or communicates with
> remote systems over the network. It might also be useful to test
> communications across formal module boundaries, where it's
> particularly important that a specific protocol be used - eg, for
> something like Prevalayer.

Indeed, and in these cases and the other appropriate use cases I'd
like to see a nicely written, widely used, standardised framework
precisely so we (I) don't have to write our (my) own.

Anyhow, talk's cheap, and once I've finished my current chunk of work
I'll try beat SSpec into shape.

frank

> My favourite testing pattern is TrivialImplementation. Instead of
> using a test double or an expensive "real" object, I often create a
> cheap/trivial implementation of the objects that collaborate with the
> objects I'm testing. For example, Monticello2 has several repository
> classes. There are implementations that store code in a single file,
> in a directory of files, on a remote machine via sockets, on a web
> server via HTTP etc. There's also a trivial implementation that just
> uses an in-memory Dictionary for storage. It's a complete
> implementation of the repository protocol, and Monticello can use it
> "for real", but it's not as robust as the other kinds of repository.
> All the repository implementations, including MemoryRepository, have a
> suite of tests that ensure that they work correctly. But when I'm
> testing other parts of Monticello that interact with a repository,
> those tests use a MemoryRepository.
>
> I know that BDD folks like to talk about testing behaviour rather than
> state, but I don't find the distinction useful. Testing state breaks
> the encapsulation of the objects under test, and couples the test too
> closely to their internal implementation. Testing behaviour using
> mocks *does the same thing*; it just restricts the implementation in a
> different way. I find it's better to give the implementation a degree
> of freedom by testing "results". Figuring out what result you're
> looking for can be difficult - it requires thinking about what a
> passing test really tells you.
>
> Here's an example - let's say we we're testing an implementation of
> Set. Here's the version that tests state:
>
> | set |
> set := Set new.
> set add: 3.
> self assert: (set instVarNamed: 'array') = #(nil nil nil 3 nil)
>
> Here we test behaviour:
>
> | set |
> mock := MockArray new: 5
> mock expect: (Message selector: #at:put: arguments: #(4 3)).
> set := Set withArray: mock.
> set add: 3.
>
> I prefer this approach. It gives the implementation a lot of freedom,
> while ensuring that it does what we really want:
>
> | set |
> set := Set new.
> set add: 3.
> self assert: (set includes: 3).
>
> In short, I agree with Hernán. Mocks can be useful, but they're often
> overused. In most cases, they're unnecessary.
>
> Colin
>




More information about the Esug-list mailing list