[rspec-users] how to pass objects from spec to formatter from before :all block?

David Chelimsky dchelimsky at gmail.com
Sun Mar 7 13:10:30 EST 2010


On Sun, Mar 7, 2010 at 7:47 AM, Jarmo Pertman <jarmo.p at gmail.com> wrote:
> Thank you for your thoughts. Unfortunately it seems that after :each
> is not run if before :all fails...
>
> And after :all is ran after example_failed in formatter. Consider spec
> like this:
>
> describe "something" do
>  before :all do
>    p "before"
>    raise
>  end
>
>  it "does" do
>    p "it"
>  end
>
>  after :each do
>    p "each"
>  end
>
>  after :all do
>    p "all"
>  end
> end
>
> Output of it will be:
> "before"
> F"all"
>
> In other words, I'd have to put @browser into options in before :all
> AND in after :each. After :each is actually a good place, because then
> if @browser object is changed within the it block, then formatter gets
> correct browser object nevertheless. It will be messier of course, but
> I thought that I'd use Spec::Runner.configure in spec_helper or
> somewhere:
> Spec::Runner.configure do |config|
>  config.before(:all) {@browser = options[:browser] =
> Watir::Browser.new}
>  config.after(:each) {options[:browser] = @browser}
> end
>
> Does it make sense? In that way i wouldn't have to write my specs by
> using any custom way (like you demonstrated with your method
> with_new_browser.
>
> It would be great of course if i wouldn't have to fill options two
> times.

Again, there was never an intent to be able to modify the options hash
at all from within an example. The fact that you can in
before/after(:each) is an unintended by-product of the implementation,
and making it available in before(:all) would require some
re-architecting that is simply not going to happen in the context of
rspec-1 now that we're actively working on rspec-2.

Rspec-2 does give you access to a metadata hash, which you can access
through a formal API from an example, before(:each) or after(:each):

describe "something" do
  it "does something" do
    running_example.metadata[:description].should eq("does something")
  end
end

At the moment you can't access it in before(:all) because there is no
running_example yet, but we should be able to provide access to it
through a new API. I'll look into that in rspec-2. I've added an issue
for it: http://github.com/rspec/rspec-core/issues/issue/6

In the mean time, for better or worse, I'd stick with a global because
it works right now. That's how I always did this sort of thing when I
was using rspec to drive WATIR or Selenium.

HTH,
David


>
> Jarmo
>
> On Mar 7, 3:12 pm, David Chelimsky <dchelim... at gmail.com> wrote:
>> On Sat, Mar 6, 2010 at 12:33 PM, Jarmo Pertman <jarm... at gmail.com> wrote:
>> > Since i'm using Watir
>> > then i usually open up the browser in
>> > before :all block like this:
>> > before :all do
>> >  @browser = Watir::Browser.new
>> > end
>>
>> > and then in the formatter I'm saving html of the browser - thus
>> > needing to access the browser object.
>>
>> You should have access to it from within each example. This would be a
>> bit noisier, but you could do this:
>>
>> before(:all) do
>>   @browser = Watir::Browser.new
>> end
>> before(:each) do
>>   options[:browser] = @browser
>> end
>>
>> Even though that's noisier, you could easily encapsulate that in a method:
>>
>> def with_new_browser
>>   before(:all) do
>>     @browser = Watir::Browser.new
>>   end
>>   before(:each) do
>>     options[:browser] = @browser
>>   end
>>   yield
>> end
>>
>> describe "the home page" do
>>   with_new_browser do
>>     it "looks awesome" do
>>       # ....
>>     end
>>     it "takes you where you want to go" do
>>       # ...
>>     end
>>   end
>> end
>>
>> > I could solve it currently by using before :each block as shown in my
>> > first post or a global variable (not nice at all), but i thought that
>> > it would be more logical to set it into options in before :all once.
>>
>> > Also, if using before :each solution and something fails in
>> > before :all, then formatter doesn't know currently anything about the
>> > browser object and cannot save the html or anything. It's little bit
>> > bad, since let's say if i do also some "setup actions" in before :all
>> > before the actual tests and what if something fails there?
>>
>> after(:each) and after(:all) are guaranteed to run regardless of what
>> happens in before(:each), before(:all), and the examples
>> themselves. So you could deliver the browser there:
>>
>> def with_new_browser
>>   before(:all) do
>>     @browser = Watir::Browser.new
>>   end
>>   yield
>>   after(:each) do
>>     options[:browser] = @browser
>>   end
>> end
>>
>> > But what would happen if example_group options would be merged with
>> > example options?
>>
>> In rspec-1 that would be problematic, but this is already supported in
>> rspec-2 out of the box, so you may want to give rspec-2 a try.
>>
>>
>>
>>
>>
>>
>>
>> > Any other solutions?
>>
>> > Jarmo
>>
>> > On Mar 6, 7:28 pm, David Chelimsky <dchelim... at gmail.com> wrote:
>> >> On Sat, Mar 6, 2010 at 11:09 AM, Jarmo Pertman <jarm... at gmail.com> wrote:
>> >> > Hello.
>>
>> >> > I need to pass something from before :all to formatter. I know that i
>> >> > could use options hash from spec and then get the value back in
>> >> > formatter, but it doesn't work when i'm doing it from before :all.
>>
>> >> > So, this work:
>>
>> >> > # in spec
>> >> > before :each do
>> >> >  options[:something] = 1
>> >> > end
>>
>> >> > # in formatter
>> >> > def example_failed(example, counter, failure)
>> >> >  puts example.options[:something] # outputs 1
>> >> >  super
>> >> > end
>>
>> >> > But if i try to do the same thing from before :all, then it doesn't
>> >> > work.
>>
>> >> > So i looked into the source of RSpec and in example/example_methods.rb
>> >> > in method set_instance_variables_from_hash there is a line which
>> >> > ignores some instance variables among with others @_proxy, which has
>> >> > this option hash initialized in before :all and that's why it's not
>> >> > getting into the formatter - in other words it is just dropped.
>>
>> >> > Is this a bug or expected behaviour? If it's expected then what's the
>> >> > reason and how could i get the desired results of passing something to
>> >> > formatter from before :all?
>>
>> >> > Can't we just pass this options hash along?
>>
>> >> It was never intended that you would set values on options from inside
>> >> an example and access them in a formatter. You've happened on
>> >> something that just happens to work because we're using a standard
>> >> Ruby data structure.
>>
>> >> The reason it won't work for before(:all) is that before(:all) gets
>> >> run before any of the examples are run - so it doesn't have access to
>> >> the options hash, which is created per example in rspec-1.
>>
>> >> What sort of information are you trying to get to your formatter?
>> >> Maybe there is a different way to do it.
>> >> _______________________________________________
>> >> rspec-users mailing list
>> >> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
>> > _______________________________________________
>> > rspec-users mailing list
>> > rspec-us... at rubyforge.org
>> >http://rubyforge.org/mailman/listinfo/rspec-users
>>
>> _______________________________________________
>> rspec-users mailing list
>> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list