El 09/07/2010, a las 04:25, Frank J. Mattia
escribió:
Seems reasonable to me. You could test with either an interaction based approach (use mocks and stubs to confirm that @object receives the “created_by” message with the expected param) or a state based approach (hit the controller action and then inspect the system state afterwards to confirm that it is in the expected state).
What I was trying to do on my own felt a lot like what you’re calling
an interaction based approach. I want to leave the behavior testing of
my app to cuke features and I’m thinking that if I’m writing a
controller spec, then it would probably be right to test the internals
of my controllers.
I wouldn’t say that “behavior” is only for Cucumber. Back when Cucumber
hadn’t even been imagined yet, RSpec was created as a “Behavior-Driven
Development” library. Behavior has always been central to what we do
with RSpec, even at the lowest levels.
I think an important question to ask yourself when writing specs is
“Why am I doing this?”, and that leads on to “What am I interested
in specifying here?”. For me it’s all about behavior. The specs have
two purposes, then: to document/show the behavior (when read), and to
confirm/test the behavior (when executed). If I find myself writing a
test that neither shows nor tests behavior, then I probably shouldn’t be
writing it.
So, with the focus always on the behavior of the action, you can proceed
to do either interaction-based or state-based testing, depending on what
feels right for each particular case. As I mentioned in my earlier
email, there are costs and benefits of each approach, and long running
debates about which method to use when, but I think the important thing
is to always try to use the best tool for the job at hand.
(As an aside, I’ve only been using RSpec for ~3
weeks now and testing in general for maybe a month. All of this is
pretty new to me… I find myself quickly becoming ‘opinionated’ about
things so if any of this sounds like nonsense, a pointer in a good
direction would be happily accepted.)
I think the best way to learn is to do what you’re already doing:
writing specs (lots of them), thinking about what you’re doing, and
when you have doubts asking questions or looking for better ways. As
time goes by you’ll not only get better at it, but your thinking will
probably evolve too. I know I’ve gone back and forth many times over the
years, and sometimes I get a surprise when I stumble over an old blog
post of mine on testing and see what I posted.
I think if you look at what the most influential people in the
Ruby/RSpec testing community have been saying over the years, you’ll see
how their ideas have been metamorphosing and changing over the years
too. It’s a natural part of thoughtful testing, I think.
El 09/07/2010, a las 06:07, Frank J. Mattia
escribió:
it “should explicitly set created_by” do
controller.stub(:current_user) { mock_user }
mock_order.should_receive(:created_by=).with(mock_user)
post :create
end
This is my newly working spec. Does this look well thought out or is
there some glaring pitfall to doing it this way?
Well, this is the way mocking and stubbing works. If you want to set an
expectation on an object that doesn’t exist yet at the time you’re
setting up the spec, you have to “chain” things so as to inject a mock
of your own at the right place, which you’ve done here. The amount of
work you have to do setting this up will vary from case to case.
This is one of the costs of the interaction-based approached, and you
have to weigh up that cost against the benefits.
Cheers,
Wincent