[rspec-users] Assumption tests
daniel.ruby at tenner.org
Tue Nov 27 11:13:38 EST 2007
Just thought I'd post an update on this, since I promised Pat that I
Ultra-detailed, "pure behaviour/interaction" specs the way I wanted
to do them has turned out to be unproductive in the long run. The
specs are too complex to write, and too hard to read, and the lack of
refactoring tools that understand rspec means they actually hinder
refactoring. Basically, they become essentially useless and a time-
consuming hindrance. (yikes!)
So, I'm now using a pragmatic middle-ground... I start off with the
idea that the spec *is* actually an outcome test, but I use a lot of
mocking whenever I feel I want it (for isolation purposes or when the
object doesn't exist yet). This means a fair bit of "behaviour/
interaction" specification seeps in, but not so much as to take over
completely like with my previous approach.
In conclusion, you were right - my approach didn't work out. The
extreme, "pure" approach doesn't work, and the best (quickest to
write, easiest to read, and most useful to execute) I've found is a
middle ground based on intuition and experience.
Well, at least I'm definitely not afraid of mocking now :-)
Thanks for the discussion last month!
On 20 Oct 2007, at 23:49 20 Oct 2007, Daniel Tenner wrote:
> On 20 Oct 2007, at 19:54 20 Oct 2007, Pat Maddox wrote:
>> You seem to believe that the only way to define behavior is in terms
>> of interactions with other objects. That is flat-out wrong. Please
>> read http://martinfowler.com/articles/mocksArentStubs.html.
> Thanks for that excellent link. I hadn't read it yet. I need to think
> some more :-)
> I think one of the reasons I've tended towards all-out behaviour
> mocking is that when you start mocking expectations, you often break
> outcome-based testing. As a good example, using another variation of
> that Account object...
> class Account
> def initialize(balance_holder)
> @balance_holder = balance_holder
> def balance
> def withdraw(amount)
> @balance_holder.decrease_by amount
> Now if @balance_holder is a pretty complex, slow object that cries
> out to be mocked, trying to test in the way that you suggested breaks
> it "should decrease the balance when an amount is withdrawn" do
> account = Account.new(@mock_balance_holder)
> In a case like this, it seems to me impossible to avoid specifying
> only behaviour, unless you actually create a full-on fake object to
> fake the behaviour of the balance_holder (which could be a bit less
> trivial than this). But if you've mocked the balance_holder like
> that, it is impossible to then test the state of the Account.
> I guess the issue comes from situations where the apparently internal
> state of an object is dependent on the state of another object. In my
> case, I have this happen fairly often when my facebook users, which
> depend on a nasty, bug-eyed facebook_session object that I definitely
> don't want to interact with in my specs (at least not with the real
> version, which is horrendously slow and bug-prone due to various
> facebook peculiarities). I don't think that's wrong design, but it
> does mean that in those cases you can't use outcome-testing at all
> (unless you are writing an integration test).
> I'm all for pragmatism but it kind of irks me that I'd have to test
> behaviours in some cases and outcomes in others. I suppose neither of
> them is black nor white, and David's suggestion that it's all down to
> balancing design forces on a case-by-case basis...
> Maybe I should get back into maths, so I can have some absolute
> truths again ;-)
> Thanks to everyone for the very useful discussion, by the way. This
> is very helpful, and I'll try to summarize this thought progression
> on my blog so that it's not lost...
> rspec-users mailing list
> rspec-users at rubyforge.org
More information about the rspec-users