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
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users