From the RSpec documentation:
It is very tempting to use before(:all) and after(:all) for situations in which it is not appropriate. before(:all) shares some (not all) state across multiple examples. This means that the examples become bound together, which is an absolute no-no in testing. You should really only ever use before(:all) to set up things that are global collaborators but not the things that you are describing in the examples.
Well-known conventional wisdom says that different test cases (in spec-speak, “examples”) should not depend on one another for state, should be runnable in any order, etc. I certainly agree with this wisdom in general, but I think there’s one case where this rule should be broken. We’ve been writing a fair number of Selenium RC tests lately for our app, using RSpec to drive Selenium RC. When writing integration tests like this, each example (in test speak, “test method”) is often a very long script with lots of shoulds/asserts in it. We lose the nice descriptive power of small examples with specific, descriptive text, and instead are faced with a choice between vague and high-level example descriptions and really long example descriptions using ugly here documents that can easily fall out of synch with the example code.
Instead, we want to be able to do something like this:
describe "A user customizing a car" do use_chained_examples before(:all) do @model = models(:spiffy) log_in go_to_car_customization_start_page end it "should first be required to select car model" do page_title.should == "Select a model" droplist("model_id").should be_present droplist("model_id").options.should == [ "(Please select a model)", models(:spiffy).name, models(:sporty).name ] droplist("model_id").selected_value.should == "" droplist("model_id").select(@model.id) click_next_button end it "should then be required to select paint color" do page_title.should == "Select #{@model.name} color" droplist("color_id").should be_present # etc. end end
A before(:each) block can be used to reset the page between each example, which we’ve found useful when testing a bunch of validations or something similar. Note too that using chained examples is not the default behavior, and must be explicitly specified by the developer, who should “know what they are doing” if they do this.
Anyway, obviously we did figure out how to make this happen, and after we’ve refined it a bit if people are interested we’ll open source our selenium rspec stuff as a plugin. Note that our selenium specs use a different spec_helper.rb than the rest of our normal specs, so we’re keeping the ability to chain examples out of our standard specs, as conventional wisdom would recommend. Let me know what you think.
I have also been playing with selenium using spec_ui and I am going to submit some patches to spec_ui. You can find a summary in my blog at http://21croissants.blogspot.com/2007/06/selenium-reports-with-screenshots-using.html
I did not know about the “use_chained_examples” option and I am going to give a try right now. Thank you for blogging about it. I have had been thinking to create a specific matcher to generate a description from all selenium actions but it would not have been very readable …
Yes, if you could share your work through a plugin, it would be great! Jean-Michel
Hi Jean-Michel,
The use_chained_examples option is something we implemented locally at CDD, and is only available through the spec-selenium plugin right now (available via svn on rubyforge: http://rubyforge.org/projects/spec-selenium/).
Recently I was added as a committer on RSpec to roll some of our work into spec:ui. I will keep you posted.
Interesting ideas in your blog post, I would like to see something similar, too. It’s an especially interesting idea for clinical informatics, particularly in the case of validated systems, when you need to document everything your software does. This is traditionally done in Word, leading to unacceptable bureaucratic overhead.
Sorry it took a while to approve your comment, I was on vacation last week.
Hi Moses,
Cheers for the update! I only see it now though: I did not check you blog
http://rubyforge.org/projects/spec-selenium/ is great! I am going to use it. I also use selenium-grid.
Any chance you update the chained example for RSpec >= 1.1.3 ?
it looks like it can work using before :all, I am a bit confused at this stage. What’s up the spec/ui project?
Hi Jean-Michel,
Funny you should ask. I’m almost finished porting the chained examples stuff to a more recent RSpec version, because we were sick of being stuck at 1.0.8 or whatever it was at work. I should have something released in the next couple weeks, and I will be releasing it to spec/ui (which is part of rspecext). specselenium will probably be deprecated (although we’ll see how it all goes in the next couple weeks).
This is an interesting idea, the chaining of examples. I’ve run into this before–the desire to walk through an entire workflow and it creates monster tests. Are you chaining in order of appearance, or do you have to name methods such that their alphabetical order is the order of execution you want?
A note on your last comment: Have you looked at Cucumber for integration testing? The rspec.info site now explicitly recommends it.
Thanks for your comment. We chain in order of appearance, nothing special needs to be done for that to happen.
Also, we haven’t looked a cucumber much yet. We have existing infrastructure that we’d like to restructure sometime, but for now it works pretty well, especially the code for the actual tests. For our team, I am not that excited about plain text tests. Developers write all of our selenium specs right now. If some day that changes, then we’ll probably get more motivated to look into cucumber.
Pingback: Inforbiomatica » Blog Archive » Turns out, cucumber/webrat/selenium is worse