[rspec-devel] Proposal: when_it syntax

David Chelimsky dchelimsky at gmail.com
Sun Oct 5 11:10:48 EDT 2008


On Sun, Oct 5, 2008 at 4:23 AM, Antti Tarvainen <antti.tarvainen at iki.fi> wrote:
> Hello.
>
>
> I propose a new syntax that helps DRY up specs when using
> one-expectation-per-example style. There have been similar proposals
> before, but no patches. As far as I know, the idea wasn't killed, just
> forgotten.
>
> The patch adds a new "when_it" method and a new parameter to the "it"
> method. "When_it" describes the action of the example, allowing "it"
> parts to describe only the expectation.
>
> The new parameter to "it" is called :implicitly, and it means that the
> expectation should be run before the "when_it" part. (That is, it is a
> mock expectation, and regards the implicit interface of the object.)
> "It" parts without the :implicitly parameter are run after the
> "when_it" part.
>
>
> Here's an example of the syntax:
>
> describe Controller do
>  before(:each) do
>    @model = mock("model").as_null_object
>    @view = mock("view").as_null_object
>    @controller = Controller.new(@model, @view)
>  end
>
>  when_it do
>    @return_value = @controller.act_on(:some_input)
>  end
>
>  it "should get data from model", :implicitly do
>    @model.should_receive(:data_for).with(:some_input)
>  end
>
>  it "should return :success" do
>    @return_value.should == :success
>  end
> end
>
>
> For a slightly longer example, see http://tinyurl.com/when-it-example .
>
> What do you think? The new syntax makes specs more DRY, but does it
> improve readability?

To be honest, I think this really hurts readability. First,
:implicitly doesn't really say what it means, which is "the implicit
action should happen after the code in this block".

Second, the fact that the action happens before some actions in the
group and after others is going to be confusing when trying to
understand a failure.

Ironically, Yehuda Katz is in the middle of working on a patch that
supports something very similar, though it doesn't handle the
before/after action choice: http://gist.github.com/14670

Here's what I'm thinking. Rather than loading up rspec with new stuff
like this that I'm personally skeptical about, what I'd rather do is
expose a legitimate extension point that would allow you to do exactly
what you're trying to do and the same for yehuda. Something like this:

Spec::Runner.configure do |config|
  config.extend_example do |example|
    # access to a wrapper for the example
    # that exposes its args hash and other
    # useful stuff
  end

  config.extend_example_group do |group|
    # access to a wrapper for the example group
    # that exposes its args hash and other
    # useful stuff
  end
end

Then you could (theoretically) do stuff like this:

GIVENS = {}

def given(name, &block)
  GIVENS[name] = block
end

given "logged in" do
  login
end

Spec::Runner.configure do |config|
  config.extend_example do |example|
    if example.args[:given]
      example.before &GIVENS[args[:given]]
    end
  end
end

That's a quick and dirty implementation (and may or may not work as
written ;) ), but just to show you the sort of power you'd have.

Maybe there's a better way, but WDYT, in general, about the idea of
having some sort of official extension points for Examples and
ExampleGroups that would make it easy for people to write (and
publish) their own extensions without fear of rspec breaking them
later?

David

>
>
> [patch]
> http://github.com/tarvaina/rspec/commits/topic/when_it_in_one_commit
> http://github.com/tarvaina/rspec-rails/commits/topic/when_it_compatibility
>
> [one expectation per example]
> http://techblog.daveastels.com/2006/08/27/one-expectation-per-example-a-remake-of-one-assertion-per-test/
>
> [old discussions]
> http://rubyforge.org/tracker/?func=detail&group_id=797&aid=10285&atid=3152
> http://rubyforge.org/pipermail/rspec-users/2007-April/001386.html
>
>
> Antti
> _______________________________________________
> rspec-devel mailing list
> rspec-devel at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-devel
>


More information about the rspec-devel mailing list