[rspec-users] Rspecing an enumerator from outside-in woes
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
> design’ – and so far I love it; it made me think about the design for
> two days before I even wrote the first spec… :)
> My most-outside class seems to be a prime candidate for an #each
> 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
> stuff yielded by #each and then validating its contents, but it seems
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
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,
> simply validates the enumrator’s #next objects. Unfortunately, this
> 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
> 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.
More information about the rspec-users