On 10/19/07, Daniel Tenner <[EMAIL PROTECTED]> wrote:
> > If I read correctly, Daniel is suggesting that this is not behaviour
> > because he's equating behaviour with interaction. This example checks
> > an outcome, not an interaction.
> >
>
> That's right, one of my axioms is that "specifying" involves
> behaviour/interaction, not state/outcome.
To be honest, I think you're way off the mark. Objects behave in two
ways: they manipulate their state, or they interact with other
objects. Both are valid types of behavior and can be used for
specification.
There's a more subtle problem with your argument though, and that's
that as far as specs are concerned, there is no state!
Example:
# given
@account = Account.new 500
# when
@account.withdraw 300
# then
@account.balance.should == 200
The behavior of this object is quite simple. However, do we know
anything about the implementation? Do we care to know?
You might reasonably think Account is implemented as
class Account
attr_reader :amount
def initialize(balance = 0)
@balance
end
def withdraw(amount)
@balance -= amount
end
end
You'd be wrong though. It's actually implemented as
class Account
def initialize(balance = 0)
Transaction.new self, balance
end
def withdraw(amount)
Transaction.new self, -amount
end
def balance
Transaction.for(self).inject(0) { |sum, t| sum += t.amount }
end
end
(that's the beauty of mailing list examples - I'm always right! :)
Calling withdraw doesn't reduce the account balance. It reduces the
balance reported by the account. It's a subtle distinction, and one
that's not important to think about 99% of the time. Hopefully though
you see why it's a fallacy to discount state-based testing as a valid
specification technique. As long as you're using an object's API, and
not digging into it's internal state as in David's evil example,
you're dealing with behavior.
Pat
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users