On Jan 24, 2008, at 4:36 AM, Pat Maddox wrote: > > On Jan 22, 2008 10:26 PM, David Chelimsky <[EMAIL PROTECTED]> > wrote: >> On Jan 23, 2008 12:04 AM, Scott Taylor >> <[EMAIL PROTECTED]> wrote: >>> >>> On Jan 23, 2008, at 12:02 AM, David Chelimsky wrote: >>> >>>> On Jan 22, 2008 10:49 PM, Jonathan Linowes >>>> <[EMAIL PROTECTED]> wrote: >>>>> Hi >>>>> >>>>> I've spec'd a class and they pass. >>>>> >>>>> Now I'd like to assure that any subclass of this class also passes >>>>> the same specs. >>>>> Any suggestions for a clever way to handle this? >>>>> I'd prefer to keep the existing specs as is (eg instead of moving >>>>> everything into shared behaviors, or doing something to all the >>>>> 'describe' lines) >>>> >>>> How about: >>>> >>>> [Subclass1, Subclass2, BaseClass].each do |klass| >>>> describe klass do >>>> ... >>>> end >>>> end >>> >>> That's sort of funny, being that I posted this solution on >>> Courtney's >>> blog yesterday. >> >> I saw that. I've also done this before :) >> >>> Is this what you actually use in this sort of situations? Are there >>> other (better, or worse) alternatives? >> >> I usually stick w/ shared example groups, but I sometimes use an >> iterator like this. Not sure why. I'll think about it. > > I think using an iterator here is weird, and muddles the intent of > the specs. > > Think of what it means to define a class and a subclass. > > class Foo > ... some behavior ... > end > > class Bar < Foo > ... all of Foo's behavior ... > ... some specialized behavior ... > end > > You don't define all the behavior in Bar - you get a bunch of it from > Foo for free, and then specialize whatever you need. Your specs > should be similar in spirit.
In a normal setting, I'd agree with you. In the case where I used it, there was STI involved, and the subclasses had almost no unique behaviour (except one or two methods which were over-ridden). > > shared_examples_for("the foo role") do > it "should have some behavior" > ... > end > > The downside is you end up with > > describe Foo do > it_should_behave_like "the foo role" > end > > to specify the behavior, which feels pretty weak to me. The trouble with the shared specs is that you have to do the same setup multiple times, in various specs. > > Though I assume you feel somewhat similarly, so I'd be interested to > know when you use an iterator for full example groups. > > Actually one example I remember is when I wrote a macro that added a > bunch of methods to a class...I wrote the initial example group for > just one attribute name. Then when I extracted the macro, I just > iterated through a bunch of names over the example group. So it can > be useful. Although a whole class feels too coarse grained for that > approach, to me. > > I do use iterators a bunch for stuff like > > [:name, :email, :phone, :address].each do |field| > it "should require a #{field}" do > u = build_user(field => nil) > u.should_not be_valid > u.should have(1).error_on(field) > end > end > > Also, since I'm close to the subject, here's a little tip. I've seen > people write specs like: > > it "should require valid attributes" do > [:name, :email, :phone, :address].each do |field| > u = build_user(field => nil) > u.should_not be_valid > u.should have(1).error_on(field) > end > end > > but that sucks, because if the example fails, you don't have any clue > why. Cause it'll just say that user is invalid, but doesn't tell you > which field is blank. Yeah, I agree. It's also violating the one test per test case rule. If you had ordered the tests in the opposite manner, it wouldn't be a problem. I usually still use valid?, even though it's less informative, since I let FixtureReplacement take care of making it a valid record in the first place: it "should not be valid with a firstname" do new_user(:firstname => nil).should_not be_valid end it "should be valid with valid attributes" do new_user.should be_valid end Scott _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users