Jarmo Pertman
2010-Mar-06 17:09 UTC
[rspec-users] how to pass objects from spec to formatter from before :all block?
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? Jarmo
David Chelimsky
2010-Mar-06 17:28 UTC
[rspec-users] how to pass objects from spec to formatter from before :all block?
On Sat, Mar 6, 2010 at 11:09 AM, Jarmo Pertman <jarmo.p 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.
Jarmo Pertman
2010-Mar-06 18:33 UTC
[rspec-users] how to pass objects from spec to formatter from before :all block?
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. 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? But what would happen if example_group options would be merged with example options? 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
David Chelimsky
2010-Mar-07 13:12 UTC
[rspec-users] how to pass objects from spec to formatter from before :all block?
On Sat, Mar 6, 2010 at 12:33 PM, Jarmo Pertman <jarmo.p 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-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Jarmo Pertman
2010-Mar-07 13:47 UTC
[rspec-users] how to pass objects from spec to formatter from before :all block?
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
David Chelimsky
2010-Mar-07 18:10 UTC
[rspec-users] how to pass objects from spec to formatter from before :all block?
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 >