[mocha-developer] Organizing tests and mocha expectations

David Chelimsky dchelimsky at gmail.com
Tue Oct 10 07:59:03 EDT 2006


On 10/10/06, James Mead <jamesmead44 at gmail.com> wrote:
> On 09/10/06, Bryan Helmkamp <bhelmkamp at gmail.com> wrote:
> > One consideration I'd like to throw out there is the duplication of
> > the returned value (or, equivalently, the raised exception).  For my
> > original example, I don't see a need to re-specify the results for the
> > save!() and find() calls when I add my expectations.
> >
>
> Good point. Actually going with suggestion 3 would mean you didn't need to
> repeat anything - basically the key difference for this case is that you
> have a means of modifying an existing expectation - in particular the
> ability to make it assert (and perhaps to stop it asserting).

For what it's worth - feel free to disagree - but I really feel
strongly that suggestion #3 is the wrong direction:

# suggestion 3
call_to_expected_method = object.stubs(:expected_method).returns(:result)
expect(call_to_expected_method).with(:parameter1,
:parameter2).returns(:result) # replaces stubbing expectation

Slinging the expectation around in the specs is exposing mocha's
implementation to the spec-writer. This is going to lead to specs that
are much more difficult to understand when looking back at them. Also,
it's going to bind mocha to this particular implementation. Should you
guys to decide to return some different object, a wrapper of some
kind, or whatever, you'd be screwed.

Bryan's concern about duplicating the return value makes sense only
when you want the same return value. What if you want a different one
coming from the stub than from the subsequent expectation? The
duplication of the return value in this case actually helps the reader
of the spec to understand that "in this instance, we're expecting
something slightly different, but we're going to return the same
thing".

The second suggestion you had makes the binding between the stub and
the expectation clear to the reader and leaves you the flexibility to
return the same values or different values:

# suggestion 2
object.stubs(:expected_method).returns(:result)
object.expects(:expected_method, :replace => true).with(:parameter1,
:parameter2).returns(:result)

Bryan - in your original example you stated that following rspec's
methodology makes you want to have the spec broken into three separate
specs. I don't think that's really necessary in this case. In fact,
binding specs together in any way is the antithesis of rspec's
methodology. Every spec should run completely independently from the
others and should never depend on state left behind by another spec.

The spec name is "update client invalid data should render edit form",
so (if I understand correctly - maybe I don't) the fact that the
client data is invalid is not really the issue. The goal is that when
AR raises RecordInvalid you should render the edit form. The spec you
suggested has some information in it that is not relevant to the
meaning of the spec - specifically the stuff about attributes. To that
end, a single spec w/ less information would be just fine:

context "update client invalid data" do
  include ClientsControllerSpecHelper

  specify "should render edit form" do
    setup_controller

    @client = mock
    Client.expects(:find).with("1").returns(@client)

    @client.expects(:save!).raises(
      ActiveRecord::RecordInvalid.new(
        stub(:errors => stub(:full_messages => []))
      )
    )

    @controller.expects(:render).with(:action => "edit")

    put :update, :id => 1
  end
end

Does that all make sense? Apologies for the soap-boxy nature of all of
this, but a primary goal of rspec is to bring us back to specs (tests,
whatever) that are readable, understandable and easy to maintain. DRY
is a very valuable principle, but it is not the only principle. In
specs, DRY and clarity are often at odds and need to be balanced. When
only one or the other can be served, for my money, clarity wins.

Thanks for listening.

Cheers,
David


>
> --
>
> James.
> http://blog.floehopper.org
> _______________________________________________
> mocha-developer mailing list
> mocha-developer at rubyforge.org
> http://rubyforge.org/mailman/listinfo/mocha-developer
>
>


More information about the mocha-developer mailing list