So, I''ve been following the recommendations for controller specs here:
http://blog.davidchelimsky.net/articles/2006/11/09/tutorial-rspec-stubs-and-mocks
Most notably: a single expectation per specify block; the setup block
contains only stubs; mock expectations each get their own specify
block. (I''m still using 0.8, so I haven''t gotten the
describe/it
goodness yet.)
I don''t really mind the stub/mock duplication (between setup and the
specifications). What''s annoying me is the action duplication.
"get
''create''" is called in each specify block, sometimes
before the actual
specification, sometimes afterward, depending on whether it''s a mock
expectation or a state expectation.
So I played around with creating the following module and then
extending my context with it.
module MockSpecHelpers
def expect_that_it(msg)
specify msg do
yield
action
end
end
def then_it(msg)
specify msg do
action
yield
end
end
end
in the context block, I would then "def action do get
''create'' end".
And I would replace the following specify blocks
specify "should create a new person on GET to create" do
Person.should_receive(:new).and_return(@person)
get ''create''
end
specify "should assign new person to template on GET to create" do
get ''create''
assigns[:person].should_be @person
end
with
expect_that_it "should create a new person on GET to create" do
Person.should_receive(:new).and_return(@person)
end
then_it "should assign new person to template on GET to create" do
assigns[:person].should_be @person
end
The problem is that my weak Ruby metaprogramming fu has completely
failed me. :-) I can''t figure out how to get the block to be
evaluated in a context that has access to the appropriate context
methods (assigns, response, session, etc). I get errors like the
following:
NameError in ''GET /controller/action/1234 should render the foobar
template''
undefined local variable or method `response'' for
#<Spec::Runner::ContextEvalModule:0xb6def95c>
(Usually the "expect_that_it" blocks work fine, because they
aren''t
dependent on anything that is specific to their EvalContext.)
Does someone know how I could get this working?
I also thought about making an alias for setup called "given" and
instead of "action" it could be "when_action" to more
closely follow
the "given/expect/when/then" pattern and naming conventions.
Does this even look like a good idea, or is there a better way? Would
it make more sense to open the EvalContext rather than trying to
extend a module?
--
Nick
Your''s is a good question. I too have been looking for ways to DRY up
my controller tests. The more I am starting to obey a CRUD-only
design, the more duplication I am encountering in these specs. Right
now, I am combating this dilemma by making a bunch of methods in
spec_helper that define _context_ and _specify_ statements, such as:
def specify_should_handle_an_invalid_id_nicely(params)
controller = "#{params[:controller].camelize}Controller"
model = params[:controller].classify.constantize
params[:redirect_to] ||= { :action => ''index'' }
params[:actions] ||= [:edit, :update, :show, :destroy]
params[:actions].to_a.each do |action|
context "#{controller}##{action}, given an id" do
controller_name params[:controller]
specify "should call #{model}.find_by_id, instead of
#{model}.find" do
model.should_receive(:find_by_id).with("the id")
send(:process, action, :id => "the id")
end
end
context "#{controller}##{action}, not given a valid id" do
controller_name params[:controller]
setup do
model.stub!(:find_by_id)
end
specify "should redirect_to #{params[:redirect_to]}" do
send(:process, action)
response.should_redirect_to params[:redirect_to]
end
specify "should populate the flash with a message indicating
that the record wasn''t found" do
send(:process, action)
flash[:notice].should == "#{model} not found"
end
end
end
end
This approach is obviously clunky, and I would myself like a better
way to specify controller-wide contracts, as it were. Just as above,
any action that requires an id as a parameter should behave a certain
way, and I shouldn''t have to define this behavior in each
controller''s
specification; it should be application-wide.
-Chris
On 4/11/07, nicholas a. evans <nick at ekenosen.net>
wrote:> So, I''ve been following the recommendations for controller specs
here:
>
http://blog.davidchelimsky.net/articles/2006/11/09/tutorial-rspec-stubs-and-mocks
>
> Most notably: a single expectation per specify block; the setup block
> contains only stubs; mock expectations each get their own specify
> block. (I''m still using 0.8, so I haven''t gotten the
describe/it
> goodness yet.)
>
> I don''t really mind the stub/mock duplication (between setup and
the
> specifications). What''s annoying me is the action duplication.
"get
> ''create''" is called in each specify block, sometimes
before the actual
> specification, sometimes afterward, depending on whether it''s a
mock
> expectation or a state expectation.
>
> So I played around with creating the following module and then
> extending my context with it.
>
> module MockSpecHelpers
> def expect_that_it(msg)
> specify msg do
> yield
> action
> end
> end
> def then_it(msg)
> specify msg do
> action
> yield
> end
> end
> end
>
> in the context block, I would then "def action do get
''create'' end".
> And I would replace the following specify blocks
>
> specify "should create a new person on GET to create" do
> Person.should_receive(:new).and_return(@person)
> get ''create''
> end
>
> specify "should assign new person to template on GET to create"
do
> get ''create''
> assigns[:person].should_be @person
> end
>
> with
>
> expect_that_it "should create a new person on GET to create" do
> Person.should_receive(:new).and_return(@person)
> end
>
> then_it "should assign new person to template on GET to create"
do
> assigns[:person].should_be @person
> end
>
> The problem is that my weak Ruby metaprogramming fu has completely
> failed me. :-) I can''t figure out how to get the block to be
> evaluated in a context that has access to the appropriate context
> methods (assigns, response, session, etc). I get errors like the
> following:
>
> NameError in ''GET /controller/action/1234 should render the foobar
template''
> undefined local variable or method `response'' for
> #<Spec::Runner::ContextEvalModule:0xb6def95c>
>
> (Usually the "expect_that_it" blocks work fine, because they
aren''t
> dependent on anything that is specific to their EvalContext.)
>
> Does someone know how I could get this working?
>
> I also thought about making an alias for setup called "given" and
> instead of "action" it could be "when_action" to more
closely follow
> the "given/expect/when/then" pattern and naming conventions.
>
> Does this even look like a good idea, or is there a better way? Would
> it make more sense to open the EvalContext rather than trying to
> extend a module?
>
> --
> Nick
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
On 4/27/07, Chris Hoffman <bosshoff at gmail.com> wrote:> Your''s is a good question. I too have been looking for ways to DRY up > my controller tests. The more I am starting to obey a CRUD-only > design, the more duplication I am encountering in these specs. Right > now, I am combating this dilemma by making a bunch of methods in > spec_helper that define _context_ and _specify_ statements, such as: > > def specify_should_handle_an_invalid_id_nicely(params) > controller = "#{params[:controller].camelize}Controller" > model = params[:controller].classify.constantize > params[:redirect_to] ||= { :action => ''index'' } > params[:actions] ||= [:edit, :update, :show, :destroy] > > params[:actions].to_a.each do |action| > context "#{controller}##{action}, given an id" do > controller_name params[:controller] > > specify "should call #{model}.find_by_id, instead of #{model}.find" do > model.should_receive(:find_by_id).with("the id") > send(:process, action, :id => "the id") > end > end > > context "#{controller}##{action}, not given a valid id" do > controller_name params[:controller] > > setup do > model.stub!(:find_by_id) > end > > specify "should redirect_to #{params[:redirect_to]}" do > send(:process, action) > response.should_redirect_to params[:redirect_to] > end > > specify "should populate the flash with a message indicating > that the record wasn''t found" do > send(:process, action) > flash[:notice].should == "#{model} not found" > end > end > end > end > > This approach is obviously clunky, and I would myself like a better > way to specify controller-wide contracts, as it were. Just as above, > any action that requires an id as a parameter should behave a certain > way, and I shouldn''t have to define this behavior in each controller''s > specification; it should be application-wide.Would http://rubyforge.org/tracker/?func=detail&group_id=797&aid=9605&atid=3151 satisfy your needs?
That has some potential, indeed. Is there a URL you can point me to that will instruct me on how to install the HEAD of the RSpec repository? It looks like I require 0.9 to take advantage of this patch. Thanks. -Chris On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 4/27/07, Chris Hoffman <bosshoff at gmail.com> wrote: > > Your''s is a good question. I too have been looking for ways to DRY up > > my controller tests. The more I am starting to obey a CRUD-only > > design, the more duplication I am encountering in these specs. Right > > now, I am combating this dilemma by making a bunch of methods in > > spec_helper that define _context_ and _specify_ statements, such as: > > > > def specify_should_handle_an_invalid_id_nicely(params) > > controller = "#{params[:controller].camelize}Controller" > > model = params[:controller].classify.constantize > > params[:redirect_to] ||= { :action => ''index'' } > > params[:actions] ||= [:edit, :update, :show, :destroy] > > > > params[:actions].to_a.each do |action| > > context "#{controller}##{action}, given an id" do > > controller_name params[:controller] > > > > specify "should call #{model}.find_by_id, instead of #{model}.find" do > > model.should_receive(:find_by_id).with("the id") > > send(:process, action, :id => "the id") > > end > > end > > > > context "#{controller}##{action}, not given a valid id" do > > controller_name params[:controller] > > > > setup do > > model.stub!(:find_by_id) > > end > > > > specify "should redirect_to #{params[:redirect_to]}" do > > send(:process, action) > > response.should_redirect_to params[:redirect_to] > > end > > > > specify "should populate the flash with a message indicating > > that the record wasn''t found" do > > send(:process, action) > > flash[:notice].should == "#{model} not found" > > end > > end > > end > > end > > > > This approach is obviously clunky, and I would myself like a better > > way to specify controller-wide contracts, as it were. Just as above, > > any action that requires an id as a parameter should behave a certain > > way, and I shouldn''t have to define this behavior in each controller''s > > specification; it should be application-wide. > > Would http://rubyforge.org/tracker/?func=detail&group_id=797&aid=9605&atid=3151 > satisfy your needs? > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 4/11/07, nicholas a. evans <nick at ekenosen.net> wrote:> So, I''ve been following the recommendations for controller specs here: > http://blog.davidchelimsky.net/articles/2006/11/09/tutorial-rspec-stubs-and-mocks > > Most notably: a single expectation per specify block; the setup block > contains only stubs; mock expectations each get their own specify > block. (I''m still using 0.8, so I haven''t gotten the describe/it > goodness yet.) > > I don''t really mind the stub/mock duplication (between setup and the > specifications). What''s annoying me is the action duplication. "get > ''create''" is called in each specify block, sometimes before the actual > specification, sometimes afterward, depending on whether it''s a mock > expectation or a state expectation. > > So I played around with creating the following module and then > extending my context with it. > > module MockSpecHelpers > def expect_that_it(msg) > specify msg do > yield > action > end > end > def then_it(msg) > specify msg do > action > yield > end > end > end > > in the context block, I would then "def action do get ''create'' end". > And I would replace the following specify blocks > > specify "should create a new person on GET to create" do > Person.should_receive(:new).and_return(@person) > get ''create'' > end > > specify "should assign new person to template on GET to create" do > get ''create'' > assigns[:person].should_be @person > end > > with > > expect_that_it "should create a new person on GET to create" do > Person.should_receive(:new).and_return(@person) > end > > then_it "should assign new person to template on GET to create" do > assigns[:person].should_be @person > endI like the idea of binding the examples to some method that gets run before or after the example. There is a similar RFE already in the tracker http://rubyforge.org/tracker/?func=detail&group_id=797&aid=10285&atid=3152. The problem is coming up with the right language. It think expect_that_it and then_it would encourage one to write all of the expect_that_its first and the then_its last. It also seems to indicate a relationship between the examples, even though no such relationship exists. In the RFE I mentioned, I proposed something like ... it "should do something", during_event do That seems to work well, but its counterpart ... it "should leave some state", after_event do leaves me cold. It especially fails to align w/ your example "should assign new person to template on GET to create", which seems like a great way to express the behaviour, but followed by "after_event" doesn''t really read correctly. Any other suggestions? In general, I''m much more inclined to favor an additional parameter passed to #it over a new method name. Cheers, David
On 4/27/07, Chris Hoffman <chris.c.hoffman at gmail.com> wrote:> That has some potential, indeed. Is there a URL you can point me to > that will instruct me on how to install the HEAD of the RSpec > repository? It looks like I require 0.9 to take advantage of this > patch. Thanks.Actually, the patch hasn''t been applied yet. I was just asking to get your opinion. As for using trunk in a rails project, take a look at http://rspec.rubyforge.org/documentation/rails/install.html. Cheers, David> > -Chris > > On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > On 4/27/07, Chris Hoffman <bosshoff at gmail.com> wrote: > > > Your''s is a good question. I too have been looking for ways to DRY up > > > my controller tests. The more I am starting to obey a CRUD-only > > > design, the more duplication I am encountering in these specs. Right > > > now, I am combating this dilemma by making a bunch of methods in > > > spec_helper that define _context_ and _specify_ statements, such as: > > > > > > def specify_should_handle_an_invalid_id_nicely(params) > > > controller = "#{params[:controller].camelize}Controller" > > > model = params[:controller].classify.constantize > > > params[:redirect_to] ||= { :action => ''index'' } > > > params[:actions] ||= [:edit, :update, :show, :destroy] > > > > > > params[:actions].to_a.each do |action| > > > context "#{controller}##{action}, given an id" do > > > controller_name params[:controller] > > > > > > specify "should call #{model}.find_by_id, instead of #{model}.find" do > > > model.should_receive(:find_by_id).with("the id") > > > send(:process, action, :id => "the id") > > > end > > > end > > > > > > context "#{controller}##{action}, not given a valid id" do > > > controller_name params[:controller] > > > > > > setup do > > > model.stub!(:find_by_id) > > > end > > > > > > specify "should redirect_to #{params[:redirect_to]}" do > > > send(:process, action) > > > response.should_redirect_to params[:redirect_to] > > > end > > > > > > specify "should populate the flash with a message indicating > > > that the record wasn''t found" do > > > send(:process, action) > > > flash[:notice].should == "#{model} not found" > > > end > > > end > > > end > > > end > > > > > > This approach is obviously clunky, and I would myself like a better > > > way to specify controller-wide contracts, as it were. Just as above, > > > any action that requires an id as a parameter should behave a certain > > > way, and I shouldn''t have to define this behavior in each controller''s > > > specification; it should be application-wide. > > > > Would http://rubyforge.org/tracker/?func=detail&group_id=797&aid=9605&atid=3151 > > satisfy your needs? > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Oh, so I wouldn''t be able to take advantage of the patch if I applied it myself (e.g., lots of bugs )? I''m sure you can glean my opinion of the idea from the fact that I would like to start using it right away :) It seems like a generalized solution that wouldn''t be specific to rails, but easily amenable to it, which works for me. -Chris On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 4/27/07, Chris Hoffman <chris.c.hoffman at gmail.com> wrote: > > That has some potential, indeed. Is there a URL you can point me to > > that will instruct me on how to install the HEAD of the RSpec > > repository? It looks like I require 0.9 to take advantage of this > > patch. Thanks. > > Actually, the patch hasn''t been applied yet. I was just asking to get > your opinion. > > As for using trunk in a rails project, take a look at > http://rspec.rubyforge.org/documentation/rails/install.html. > > Cheers, > David > > > > > > > -Chris > > > > On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > > On 4/27/07, Chris Hoffman <bosshoff at gmail.com> wrote: > > > > Your''s is a good question. I too have been looking for ways to DRY up > > > > my controller tests. The more I am starting to obey a CRUD-only > > > > design, the more duplication I am encountering in these specs. Right > > > > now, I am combating this dilemma by making a bunch of methods in > > > > spec_helper that define _context_ and _specify_ statements, such as: > > > > > > > > def specify_should_handle_an_invalid_id_nicely(params) > > > > controller = "#{params[:controller].camelize}Controller" > > > > model = params[:controller].classify.constantize > > > > params[:redirect_to] ||= { :action => ''index'' } > > > > params[:actions] ||= [:edit, :update, :show, :destroy] > > > > > > > > params[:actions].to_a.each do |action| > > > > context "#{controller}##{action}, given an id" do > > > > controller_name params[:controller] > > > > > > > > specify "should call #{model}.find_by_id, instead of #{model}.find" do > > > > model.should_receive(:find_by_id).with("the id") > > > > send(:process, action, :id => "the id") > > > > end > > > > end > > > > > > > > context "#{controller}##{action}, not given a valid id" do > > > > controller_name params[:controller] > > > > > > > > setup do > > > > model.stub!(:find_by_id) > > > > end > > > > > > > > specify "should redirect_to #{params[:redirect_to]}" do > > > > send(:process, action) > > > > response.should_redirect_to params[:redirect_to] > > > > end > > > > > > > > specify "should populate the flash with a message indicating > > > > that the record wasn''t found" do > > > > send(:process, action) > > > > flash[:notice].should == "#{model} not found" > > > > end > > > > end > > > > end > > > > end > > > > > > > > This approach is obviously clunky, and I would myself like a better > > > > way to specify controller-wide contracts, as it were. Just as above, > > > > any action that requires an id as a parameter should behave a certain > > > > way, and I shouldn''t have to define this behavior in each controller''s > > > > specification; it should be application-wide. > > > > > > Would http://rubyforge.org/tracker/?func=detail&group_id=797&aid=9605&atid=3151 > > > satisfy your needs? > > > _______________________________________________ > > > rspec-users mailing list > > > rspec-users at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 4/27/07, Chris Hoffman <chris.c.hoffman at gmail.com> wrote:> Oh, so I wouldn''t be able to take advantage of the patch if I applied > it myself (e.g., lots of bugs )?We haven''t tried to apply it. It might work just fine. Aslak and I need to take a closer look at it before we agree to apply it and there are other priorities for both of us both in and out of rspec at the moment. If you do apply it and it works, please report to this list about your experience. Cheers, David> I''m sure you can glean my opinion of > the idea from the fact that I would like to start using it right away > :) > > It seems like a generalized solution that wouldn''t be specific to > rails, but easily amenable to it, which works for me. > > -Chris > > On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > On 4/27/07, Chris Hoffman <chris.c.hoffman at gmail.com> wrote: > > > That has some potential, indeed. Is there a URL you can point me to > > > that will instruct me on how to install the HEAD of the RSpec > > > repository? It looks like I require 0.9 to take advantage of this > > > patch. Thanks. > > > > Actually, the patch hasn''t been applied yet. I was just asking to get > > your opinion. > > > > As for using trunk in a rails project, take a look at > > http://rspec.rubyforge.org/documentation/rails/install.html. > > > > Cheers, > > David > > > > > > > > > > > > -Chris > > > > > > On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > > > On 4/27/07, Chris Hoffman <bosshoff at gmail.com> wrote: > > > > > Your''s is a good question. I too have been looking for ways to DRY up > > > > > my controller tests. The more I am starting to obey a CRUD-only > > > > > design, the more duplication I am encountering in these specs. Right > > > > > now, I am combating this dilemma by making a bunch of methods in > > > > > spec_helper that define _context_ and _specify_ statements, such as: > > > > > > > > > > def specify_should_handle_an_invalid_id_nicely(params) > > > > > controller = "#{params[:controller].camelize}Controller" > > > > > model = params[:controller].classify.constantize > > > > > params[:redirect_to] ||= { :action => ''index'' } > > > > > params[:actions] ||= [:edit, :update, :show, :destroy] > > > > > > > > > > params[:actions].to_a.each do |action| > > > > > context "#{controller}##{action}, given an id" do > > > > > controller_name params[:controller] > > > > > > > > > > specify "should call #{model}.find_by_id, instead of #{model}.find" do > > > > > model.should_receive(:find_by_id).with("the id") > > > > > send(:process, action, :id => "the id") > > > > > end > > > > > end > > > > > > > > > > context "#{controller}##{action}, not given a valid id" do > > > > > controller_name params[:controller] > > > > > > > > > > setup do > > > > > model.stub!(:find_by_id) > > > > > end > > > > > > > > > > specify "should redirect_to #{params[:redirect_to]}" do > > > > > send(:process, action) > > > > > response.should_redirect_to params[:redirect_to] > > > > > end > > > > > > > > > > specify "should populate the flash with a message indicating > > > > > that the record wasn''t found" do > > > > > send(:process, action) > > > > > flash[:notice].should == "#{model} not found" > > > > > end > > > > > end > > > > > end > > > > > end > > > > > > > > > > This approach is obviously clunky, and I would myself like a better > > > > > way to specify controller-wide contracts, as it were. Just as above, > > > > > any action that requires an id as a parameter should behave a certain > > > > > way, and I shouldn''t have to define this behavior in each controller''s > > > > > specification; it should be application-wide. > > > > > > > > Would http://rubyforge.org/tracker/?func=detail&group_id=797&aid=9605&atid=3151 > > > > satisfy your needs? > > > > _______________________________________________ > > > > rspec-users mailing list > > > > rspec-users at rubyforge.org > > > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > > > > _______________________________________________ > > > rspec-users mailing list > > > rspec-users at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote:> I like the idea of binding the examples to some method that gets run > before or after the example. There is a similar RFE already in the > tracker http://rubyforge.org/tracker/?func=detail&group_id=797&aid=10285&atid=3152.I hadn''t seen that one. I was originally also thinking about some sort of magic handling whereby mocks are automatically run before and state expectations are automatically run afterwards. But I agree with you: that magic comes at the cost of losing much clarity.> The problem is coming up with the right language.Yes.> In the RFE I mentioned, I proposed something like ... > > it "should do something", during_event doI like that a *lot*. :-)> That seems to work well, but its counterpart ... > > it "should leave some state", after_event do > > leaves me cold. It especially fails to align w/ your example "should > assign new person to template on GET to create", which seems like a > great way to express the behaviour, but followed by "after_event" > doesn''t really read correctly.Could during_event, before_event, after_event, when_event, by_end_of_event, on_event (and perhaps some number of other aliases with the same similar before/after behaviour, but different names for readability in different contexts) also be made to append text to the specification string? Likewise, the event itself could include a description. e.g. describe PeopleController do before do @person = mock_model(Person) Person.stub!(:new).and_return(@person) end event "GET to #create" do get "create", :foo => "bar" end it "should create a new person", during_event do Person.should_receive(:new).and_return(@person) end it "should assign new person to template", on_event do assigns[:person].should_be @person end end could generate the following sentences: PeopleController should create a new person during GET to #create PeopleController should assign new person to template on GET to #create What do you think of that? I''m still not sure that "on_event" clearly represents "event then expectation" as clearly as something else might... but it works for me, and it produces the nice string.> In general, I''m much more inclined to favor an additional parameter > passed to #it over a new method name.Yeah, I hadn''t even thought about something like that. I like it a *lot*. -- Nick
On 4/27/07, nicholas a. evans <nick at ekenosen.net> wrote:> On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > I like the idea of binding the examples to some method that gets run > > before or after the example. There is a similar RFE already in the > > tracker http://rubyforge.org/tracker/?func=detail&group_id=797&aid=10285&atid=3152. > > I hadn''t seen that one. I was originally also thinking about some > sort of magic handling whereby mocks are automatically run before and > state expectations are automatically run afterwards. But I agree with > you: that magic comes at the cost of losing much clarity. > > > The problem is coming up with the right language. > > Yes. > > > In the RFE I mentioned, I proposed something like ... > > > > it "should do something", during_event do > > I like that a *lot*. :-) > > > That seems to work well, but its counterpart ... > > > > it "should leave some state", after_event do > > > > leaves me cold. It especially fails to align w/ your example "should > > assign new person to template on GET to create", which seems like a > > great way to express the behaviour, but followed by "after_event" > > doesn''t really read correctly. > > Could during_event, before_event, after_event, when_event, > by_end_of_event, on_event (and perhaps some number of other aliases > with the same similar before/after behaviour, but different names for > readability in different contexts) also be made to append text to the > specification string? Likewise, the event itself could include a > description. > > e.g. > > describe PeopleController do > before do > @person = mock_model(Person) > Person.stub!(:new).and_return(@person) > end > event "GET to #create" do > get "create", :foo => "bar" > end > it "should create a new person", during_event do > Person.should_receive(:new).and_return(@person) > end > it "should assign new person to template", on_event do > assigns[:person].should_be @person > end > end > > could generate the following sentences: > > PeopleController should create a new person during GET to #create > PeopleController should assign new person to template on GET to #create > > What do you think of that? I''m still not sure that "on_event" clearly > represents "event then expectation" as clearly as something else > might... but it works for me, and it produces the nice string.Very nice! The trick is that we''re merging to concepts here - trying to express the intent of the example and also have it execute the right things in the right order. Words like "during" or "on" are there to coerce rspec to execute things in the right order but they mean the same thing to me in terms of expressing the example - the "when" in GWT. I''d love to come up with words that serve both execution and expression equally. Any other ideas?> > > In general, I''m much more inclined to favor an additional parameter > > passed to #it over a new method name. > > Yeah, I hadn''t even thought about something like that. I like it a *lot*. > > -- > Nick > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 4/27/07, David Chelimsky <dchelimsky at gmail.com> wrote:> Very nice! The trick is that we''re merging to concepts here - trying > to express the intent of the example and also have it execute the > right things in the right order. Words like "during" or "on" are there > to coerce rspec to execute things in the right order but they mean the > same thing to me in terms of expressing the example - the "when" in > GWT. I''d love to come up with words that serve both execution and > expression equally. Any other ideas?It seems to be a hard problem... Ideas for before_event: * during_event I really like that one, and I can''t come up with anything better... to me it communicates the execution order. Ideas for after_event: * with_event * by_the_end_of_event * by_event * upon_event PeopleController should assign new person to template with a GET to create PeopleController should assign new person to template by the end of a GET to create PeopleController should assign new person to template upon a GET to create (I added changed the event string to "a GET to create".) Both "upon" and "by_the_end_of it" seem evident to me that the expectations would need to run after the event. Is it getting closer to something good? -- Nick