assert_difference in functional tests

13 views
Skip to first unread message

Manuel González Noriega

unread,
Jul 8, 2008, 6:54:59 AM7/8/08
to shoulda
Hi,

me and some other blokes on the Spanish RoR users mailing list have
stumbled upon the following scenario when using assert_difference in
functional tests:

Say I've got something like this:

---
context 'on post to :create' do
setup do
@term = {:title => "foo", :body => 'Lorem ipsum'}
post :create, {:glossary_term => @term}
end

should_assign_to :glossary_term

should_set_the_flash_to "El término se ha creado con éxito"
should_redirect_to "edit_glossary_term_url(@glossary_term)"

end
---

Is there an elegant/best practice/DRYer approach to assert_difference
'GlossaryTerm.count' in this context? Because the block syntax for the
assertion means having the request on setup won't really work, and
removing it screws up the other macros.

So, besides moving the assert_difference to a traditional test, any
other hint?

Thank you in advance and many thanks to the Shoulda devs for their
amazing work :)









Ryan McGeary

unread,
Jul 8, 2008, 12:08:27 PM7/8/08
to sho...@googlegroups.com
Colleagues and I have had a similar want for assert_difference behavior in shoulda.  Your inquiry got me thinking, and I started to experiment.  Currently I have something that allows for the creation of a "should_differ_by" macro.  Without getting into the nitty-gritty, here is example usage:

  context "An array" do
    setup { @array = [1, 2, 3] }

    should "have a length of 3" do
      assert_equal 3, @array.length
    end

    context "after pushing an element onto it " do
      setup { @array.push(4) }

      should_differ_by 1, "@array.length"
    end
  end

I couldn't think of a way to do this without modifying shoulda, so this required a tweak to the core should method.  Basically, the modified version allows for an extra "before" proc (optional) to be passed to a should call.  This before proc runs after all the parent setups but before the current context's setups.  

I guess the "before" proc could be thought of as an extra setup that is stitched into the existing setups and only run for one particular test.  Direct usage isn't that pretty, but it allows for the construction of potentially useful macros (like should_differ_by above).

If this is something others would find value in, I will happily clean up my local experimental shoulda branch, add some more tests, and make it public.  

Regards,
Ryan

Tammer Saleh

unread,
Jul 8, 2008, 12:14:55 PM7/8/08
to sho...@googlegroups.com
We've thought about adding a :before option to should for mocking as well.

context "get to /users" do
  setup { get :index }

  should "set @users to User.finder", :before => lambda { User.expects(:finder).returns([:one]) do
    assert_equal [:one], assigns(:users)
  end
end

so I think it would be a useful addition.

david.l...@gmail.com

unread,
Jul 8, 2008, 1:23:35 PM7/8/08
to sho...@googlegroups.com
Hi Ryan,
This looks really cool, as I've had a similar desire as well.
The way I thought about it previously, was that I wanted some kind of
"around" block to wrap around the setup.
How does the should_differ_by macro work? I'm guessing that it creates
a before block that stores some temporary value, then compares the new
value with it later in the should block.

Thanks,
-David

Manuel González Noriega

unread,
Jul 8, 2008, 2:23:07 PM7/8/08
to sho...@googlegroups.com
2008/7/8 Ryan McGeary <ryan.m...@gmail.com>:

> Colleagues and I have had a similar want for assert_difference behavior in
> shoulda. Your inquiry got me thinking, and I started to experiment.
> Currently I have something that allows for the creation of a
> "should_differ_by" macro. Without getting into the nitty-gritty, here is
> example usage:
>

That looks real sweet, Ryan. Here's hoping you'll be able to release
it eventually.


--
Manuel, que
piensa que eres una excelente persona y medra en torno a
http://simplelogica.net y/o http://simplelogica.net/logicola/
Recuerda comer mucha fruta y verdura.

Ryan McGeary

unread,
Jul 8, 2008, 5:50:48 PM7/8/08
to sho...@googlegroups.com
David,


I'm guessing that it creates a before block that stores some temporary value, then compares the new value with it later in the should block.

Yes, that's exactly how should_differ_by works.  

I hope to publish something later tonight after work.

-Ryan


On Tue, Jul 8, 2008 at 1:23 PM, <david.l...@gmail.com> wrote:

Hi Ryan,
  This looks really cool, as I've had a similar desire as well.
The way I thought about it previously, was that I wanted some kind of
"around" block to wrap around the setup.
How does the should_differ_by macro work? 

Ryan McGeary

unread,
Jul 8, 2008, 9:53:56 PM7/8/08
to sho...@googlegroups.com
The branch for the :before option is now available.  Here's the lighthouse ticket that discusses it:
  http://thoughtbot.lighthouseapp.com/projects/5807-shoulda/tickets/51-add-a-before-proc-to-should-statements

Here's the relevant commit:
  http://github.com/rmm5t/shoulda/commit/e6e2f6b906edc4ecd6d7f8a77046216e308d1cf0

Tammer, et al,  I'm now working on adding the "should differ" macro.  Assuming you'd like to see this in shoulda, which syntax would you prefer?

A) should_differ_by 1, "Post.count"

B) should_differ "Post.count", :by => 1

I have mixed feelings between the two.  Option A was my original instinct, but option B allows for defaulting the :by option to 1 and thereby making it optional.  Also, option B arguably reads more clearly (to me).

Any other suggestions for the macro signature?  A verb other than "differ" might work too;  I just can't think of anything better at the moment, especially considering Active Support's assert_difference counter part.

-Ryan

Ryan McGeary

unread,
Jul 8, 2008, 10:19:49 PM7/8/08
to shoulda
> ... which syntax would you prefer?
> A) should_differ_by 1, "Post.count"
> B) should_differ "Post.count", :by => 1

I decided to ask forgiveness instead of asking for permission. I
published a branch that adds a "should_differ" macro (option B).
Here's the lighthouse ticket that discusses it:
http://thoughtbot.lighthouseapp.com/projects/5807-shoulda/tickets/52-add-should_differ-macro

If we want to change the method signature in any way, I'm okay with
that. Just let me know.

-Ryan

On Jul 8, 9:53 pm, "Ryan McGeary" <ryan.mcge...@gmail.com> wrote:
> The branch for the :before option is now available.  Here's the lighthouse
> ticket that discusses it:
>
> http://thoughtbot.lighthouseapp.com/projects/5807-shoulda/tickets/51-...
>
> Here's the relevant commit:
>
> http://github.com/rmm5t/shoulda/commit/e6e2f6b906edc4ecd6d7f8a7704621...

david.l...@gmail.com

unread,
Jul 9, 2008, 2:36:25 AM7/9/08
to sho...@googlegroups.com

I vote for the following syntax, which seems to be the most expressive:

context "Some action" do
setup do
# do some stuff equivalent to 'some action'
end

should_change "Post.count", :from => 1, :to => 2
should_change "Post.count", :from => 1 # don't care what the end
result is as long as it's different than :from
should_change "Post.count", :to => 1 # don't care what :from is
as long as the end result matches :to
should_change "@post.attribute", :from => 'foo', :to => 'bar' #
the above examples would also work with a string or any other value

# only the :by option must be numeric
should_change "Post.count", :by => 1 # don't care what :from
or :to were, as long as the difference is 1
end

-D

Earle Clubb

unread,
Jul 9, 2008, 8:13:31 AM7/9/08
to sho...@googlegroups.com
I agree that David's syntax seems more expressive.  +1.

Earle

Ryan McGeary

unread,
Jul 9, 2008, 8:16:14 AM7/9/08
to sho...@googlegroups.com
Cool, I like David's suggestions to.  I'm working on another experimental branch now that adds a should_change macro with :by, :from, and :to options.
-Ryan

Murray Steele

unread,
Jul 9, 2008, 9:57:11 AM7/9/08
to sho...@googlegroups.com
Would there be any change of another experimental branch where the "Post.count" could be code and not a string? something like:-

should_change lambda { Post.count }, :by => 1

or, because that lambda is UGLY:-

should_change :by => 1 do
  Post.count
end

Basically making it easier to get IDE support for more complex chunks of code that you expect to have changed.

Muz


2008/7/9 Ryan McGeary <ryan.m...@gmail.com>:

Ryan McGeary

unread,
Jul 9, 2008, 11:05:54 AM7/9/08
to shoulda
David's suggestions are now in another branch. Lighthouse ticket
updated:
http://thoughtbot.lighthouseapp.com/projects/5807/tickets/52-add-should_differ-macro#ticket-52-3

> Would there be any change of another experimental branch where the
> "Post.count" could be code and not a string? something like:-

Muz, I like the block syntax better than the lambda syntax, but I'm
having trouble thinking of use cases that make it worthwhile. Did you
have something specific in mind beyond IDE support? Either way, I
suggest hashing out the eval'd string version first and experimenting
with additions afterward.

-Ryan

On Jul 9, 9:57 am, "Murray Steele" <murray.ste...@gmail.com> wrote:
> Would there be any change of another experimental branch where the
> "Post.count" could be code and not a string? something like:-
>
> should_change lambda { Post.count }, :by => 1
>
> or, because that lambda is UGLY:-
>
> should_change :by => 1 do
>   Post.count
> end
>
> Basically making it easier to get IDE support for more complex chunks of
> code that you expect to have changed.
>
> Muz
>
> 2008/7/9 Ryan McGeary <ryan.mcge...@gmail.com>:
>
> > Cool, I like David's suggestions to.  I'm working on another experimental
> > branch now that adds a should_change macro with :by, :from, and :to options.
> > -Ryan
>
> > On Wed, Jul 9, 2008 at 8:13 AM, Earle Clubb <ecl...@valcom.com> wrote:
>
> >>  I agree that David's syntax seems more expressive.  +1.
>
> >> Earle
>
> >> david.lowenf...@gmail.com wrote:
>
> >> I vote for the following syntax, which seems to be the most expressive:
>
> >> context "Some action" do
> >>    setup do
> >>      # do some stuff equivalent to 'some action'
> >>    end
>
> >>    should_change "Post.count", :from => 1, :to => 2
> >>    should_change "Post.count", :from => 1  # don't care what the end
> >> result is as long as it's different than :from
> >>    should_change "Post.count", :to => 1    # don't care what :from is
> >> as long as the end result matches :to
> >>    should_change "@post.attribute", :from => 'foo', :to => 'bar'  #
> >> the above examples would also work with a string or any other value
>
> >>    # only the :by option must be numeric
> >>    should_change "Post.count", :by => 1    # don't care what :from
> >> or :to were, as long as the difference is 1
> >> end
>
> >> -D
>
> >> On Jul 8, 2008, at 6:53 PM, Ryan McGeary wrote:
>
> >>  The branch for the :before option is now available.  Here's the
> >> lighthouse ticket that discusses it:
> >>  http://thoughtbot.lighthouseapp.com/projects/5807-shoulda/tickets/51-...
>
> >> Here's the relevant commit:
> >>  http://github.com/rmm5t/shoulda/commit/e6e2f6b906edc4ecd6d7f8a7704621...

Murray Steele

unread,
Jul 9, 2008, 11:47:33 AM7/9/08
to sho...@googlegroups.com

2008/7/9 Ryan McGeary <ryan.m...@gmail.com>:


> Would there be any change of another experimental branch where the
> "Post.count" could be code and not a string? something like:-

Muz, I like the block syntax better than the lambda syntax, but I'm
having trouble thinking of use cases that make it worthwhile.  Did you
have something specific in mind beyond IDE support?  

Other than a general distaste for writing code in a string rather than writing it directly, not really.  It just looks nicer, and for me at least that's no small thing.
 
Either way, I
suggest hashing out the eval'd string version first and experimenting
with additions afterward.

Yeah, that makes sense, block support instead of strings is a total nice to have. 

Once your eval'd string version is stable / pulled in I might take a crack at the block syntax myself though, in a "put up or shut up" spirit.

Muz

david.l...@gmail.com

unread,
Jul 9, 2008, 11:51:00 AM7/9/08
to sho...@googlegroups.com
Typically, the code inside the block is what you want to execute do
the changes... like with assert_difference, which is kind of like an
"expectation".
I think the syntax below would be majorly confusing.

-D


On Jul 9, 2008, at 6:57 AM, Murray Steele wrote:

> Would there be any change of another experimental branch where the
> "Post.count" could be code and not a string? something like:-
>

Ryan McGeary

unread,
Jul 31, 2008, 12:47:58 AM7/31/08
to shoulda
Just to close the loop on this in case not everyone followed along
with the Lighthouse ticket, a new should_change macro was added a
couple of weeks ago. Here's some example usage:

context "Creating a post"
setup { Post.create }
should_change "Post.count", :by => 1
end

The macro also accepts :from and :to options. More examples:

should_change "Post.count", :from => 0, :to => 1
should_change "@value", :from => /\w/, :to => /\d/
should_change "@value", :from => String, :to => Fixnum

More details are available in the ticket's thread:
http://thoughtbot.lighthouseapp.com/projects/5807/tickets/52

A big thanks goes to David Lowenfels for helping hash out the method
signature.

-Ryan

On Jul 8, 6:54 am, Manuel González Noriega

Dan Croak

unread,
Jul 31, 2008, 1:42:32 AM7/31/08
to shoulda
Congratulations, Ryan, David, et al. This is very tight, very
powerful, and I'm sure I'll be using it immediately. Great work.
Reply all
Reply to author
Forward
0 new messages