[rspec-users] Rspecing an enumerator from outside-in woes

Matt Wynne matt at mattwynne.net
Sun Mar 1 08:27:31 EST 2009

On 28 Feb 2009, at 21:29, Shot (Piotr Szotkowski) wrote:

> I’m trying to spec a system from outside-in as an excercise in  
> ‘emergent
> design’ – and so far I love it; it made me think about the design for
> two days before I even wrote the first spec… :)

Great :)

> My most-outside class seems to be a prime candidate for an #each  
> method.
> The attached (stripped) spec carrying two of the approaches I came up
> with passes, and raises the following quesitions – any answer would be
> most appreciated!
> 1. A philosophical/kosherness question: In the finished system
> Decomposer#each will yield Decomposition objects, but as I’m specing
> from outside-in, the Decomposition class is not yet created. In the
> attached example I’m using an Array as a poor man’s Decomposition
> replacement. Is this a sane approach, or should I rather create
> a skeletal Decomposition#initialize instead?

I think you should try to write the specs so they won't have to change  
when you build the real implementation. That doesn't mean creating an  
actual Decomposition class just yet, but it does mean that you should  
return something that looks enough like one for the tests to still be  
valid when you swap one in.

> 2. The first spec shows my initial approach, with a variable polling  
> the
> stuff yielded by #each and then validating its contents, but it seems
> clumsy…

I think what you're finding clumsy here is the mocking setup. You  
don't always have to use mock objects as your 'test doubles' and often  
it's much easier (and leaves behind more flexible tests) if you use  
stubs rather than mocks.

In this case, although it's possible to create a test double for the  
Generators using RSpec's mocking framework, it's pretty awkward and  
hard to read. I would be tempted to write my own test double instead.  
Applying outside-in to the behaviour I want from the test double, I'd  
write this:

I'll leave it to you to code the #each method on the FakeGenerator,  
but hopefully you get the idea.

Notice that I just used an Array as the fake for @uv_gen - I might  
have missed something but I think that would provide an adequate  
double for the behaviour you had specified for the mock.

> 3. …so I came up with the second, Decomposer.new.to_enum approach,  
> which
> simply validates the enumrator’s #next objects. Unfortunately, this  
> does
> not seem to trigger #should_receive(:each) on the *_gen mocks and made
> me #stub!(:each) on them instead. Is this because I’m using RSpec  
> 1.1.12
> with Ruby 1.9.1, or am I missing something on how message expectations
> work with lazy iterators (and, thus, #should_receive fail properly)?

I think you're getting too far into specifying the implementation  
here. I like the #each approach better.

Hope that helps.

Matt Wynne

More information about the rspec-users mailing list