Sharing specs in a subclass

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)

thanks

linoj

On Jan 22, 2008 10:49 PM, Jonathan L. [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

cool
thx
:slight_smile:

On Jan 23, 2008, at 12:02 AM, David C. wrote:

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.

Is this what you actually use in this sort of situations? Are there
other (better, or worse) alternatives?

Scott

On Jan 23, 2008 12:04 AM, Scott T. [email protected]
wrote:

the same specs.
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 :slight_smile:

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.

Cheers,
David

On Jan 22, 2008 10:26 PM, David C. [email protected] wrote:

Now I’d like to assure that any subclass of this class also passes

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.

shared_examples_for(“the foo role”) do
it “should have some behavior”

end

describe Bar do
it_should_behave_like “the foo role”

it “should have some specialized behavior”

end

That is far more clear to me. The downside is that you also end up with

On Jan 22, 2008 10:26 PM, David C. [email protected]invalid wrote:

Now I’d like to assure that any subclass of this class also passes

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.

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.

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.

That was a bit of a tangent. It’s late, I’m loopy :slight_smile:

Pat

On Jan 24, 2008, at 4:36 AM, Pat M. wrote:

Hi
How about:

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).

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.

Also, since I’m close to the subject, here’s a little tip. I’ve seen
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

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs