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

Jarmo Pertman jarmo.p at gmail.com
Sun Mar 7 08:47:48 EST 2010


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.

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


More information about the rspec-users mailing list