[rspec-devel] Mocking in the past tense

David Chelimsky dchelimsky at gmail.com
Thu Nov 9 23:11:25 EST 2006


On 11/9/06, Jay Levitt <lists-rspec at shopwatch.org> wrote:
> I'm in the process of converting my controller specs into TRUE
> controller specs (not just semi-integration specs), and I'm realizing
> that, for the same reason we have controller.should_have_rendered.

Actually, the reason we have controller.should_have_rendered is to
make the 0.6 > 0.7 transition just a little easier. I'd just as soon
get rid of it! :)

> , we need mocking in the past tense, or - more likely - a better setup solution.
>
> The common case for a controller spec has
>
> context "/controller/something"
>    setup do
>      get 'something'
>    end
>
> and then a bunch of specs that ensure the 'something' action does what
> it's supposed to.
>
> Well, if you spec this by mocking, instead of specifying state, there's
> really no way to put that "get" into setup. If you did, then all your
> mocks would have to go into setup too - and that means your entire spec
> is in setup.
>
> Right now, I'm solving this by putting the get into a subroutine and
> calling it repeatedly in each spec.  That doesn't feel DRY.

While I agree that DRY is important in the subject code, in my opinion
DRY is overrated when it comes to specs. The problem w/ DRY is not
that you have to change things twice. The real problem is when you
don't KNOW the other place you have to change it because it's off in
some other file somewhere.

In a case like this, I like to just add a method to execute the action
and call that:

context "..." do
  def do_get
    get 'some_action'
  end

  specify "one thing" do
    do_get
    verify_something
  end

  specify "another thing" do
    expect_something
    do_get
  end
end

For me, that makes the whole thing very clear and it gets closer to
DRY w/o being nuts about doing so.

> On the
> other hand, I can't think of an improvement that doesn't have at least a
> "yield" in the middle of a spec, and I'm not sure that's such an
> improvement.
>
> Any thoughts?

The idea of past-tense mocking has come up before. The problem is that
it only provides value in a very limited subset of potential uses.
With instances of Spec::Mocks::Mock, you could do something like this:

setup do
  @mock = mock("whatever", :record_messages => true)
  @subject = Subject.new(@mock)
end

specify "..." do
  @subject.do_something
  @mock.should_have_received(:some_message).with(:some, :values)
end

But this quickly breaks down when :some_message has to return
something. And it gets more strange when dealing w/ intercepting calls
to pre-existing objects and classes.

So, for me, I'd rather absorb the subtle dampness of the do_get method
and keep the specs clear.

Thoughts?

>
> Jay
>
> _______________________________________________
> rspec-devel mailing list
> rspec-devel at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-devel
>


More information about the rspec-devel mailing list