[rspec-users] Rspecing an enumerator from outside-in woes
Shot (Piotr Szotkowski)
shot at hot.pl
Sun Mar 1 12:30:06 EST 2009
Thanks a lot, Matt, for your reply! It’s seriously most enlightening.
> On 28 Feb 2009, at 21:29, Shot (Piotr Szotkowski) wrote:
>> 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.
Hmm, interesting – so an outside-in implementation should side-step
using future classes’ constructors, and the implementation code should
actually change when the relevant classes appear?
I ended up creating a skeletal Decomposition class, but then had to
add Decomposition#==(other) – which, in turn, made me add attribute
accessors – just to be able to test against Decomposition objects in
Decomposition#== will be useful in the future, but currently it exists
solely so I can use RSpec’s ….should == Decomposition.new(…), which
seems wrong. Hmm, another thing to ponder upon – every time a new RSpec
paradigm shows me something new, some other, unrelated spec begins to
raise suspicions… :)
> 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.
Thanks a ton for the Array-based generators – I haven’t thought of that;
they are most interesting. I can’t use your example verbatim, as in my
real code Decomposer.new takes class names and only then instantiates
the relevant generators¹, but it surely opened my eyes on stubbing
objects with general-purpose classes rather than mocking them. I’ll
see how I can use them to clean-up the specs. :)
>> 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.
I think I agree – but the real question was why don’t the (lazy)
enumerator’s #next calls satisfy the mocks’ #should_receive()s –
am I missing something fundamental, or is this simply an RSpec 1.1.12
incompatibility with Ruby 1.9.1?
For reference, my original attachment: http://gist.github.com/72399 –
if you replace the #stub!()s in the second spec with #should_receive()s,
the spec breaks with (allegedly) unsatisfied expectations.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Size: 197 bytes
Desc: Digital signature
More information about the rspec-users