Re: [rspec-users] [Q] how to restructure tests for an abstract class?

2008-02-26 Thread Chuck Remes

On Feb 25, 2008, at 8:30 AM, David Chelimsky wrote:

> On Mon, Feb 25, 2008 at 6:23 AM, Chuck Remes  
> <[EMAIL PROTECTED]> wrote:
>> Thanks for asking this question. This is exactly what I was going  
>> to write,
>> but you beat me to it!
>>
>> (Sorry for the top-post; just following the last responder.)
>>
>> cr
>>
>>
>>
>> On Feb 25, 2008, at 3:30 AM, Matthijs Langenberg wrote:
>> Question is, would you duplicate the specs for all the classes that  
>> include
>> a certain module (through shared behaviour for example), or would  
>> you use
>> one set of specs for just the module, and specify that a class should
>> include that module?
>
> Matthijs - I'd throw the same question back to you. Have you tried
> both approaches? How have they worked out for you?
>
> I won't wait for your answer :). But I am curious about other people's
> experiences with this.
>
> I can tell you this from my own experience - I tend to use shared
> groups for this for a couple of reasons. One, I like to see the specs
> for each object.

I thought I'd share my experiences with the group. Please recall I'm  
new at BDD/TDD so I may get some of the terminology wrong or whatever.

So I have a class that, by itself, doesn't do anything. Concrete  
subclasses are necessary to flesh out a few characteristics before the  
parent class code can perform its magic. This is an abstract class  
which I'm told isn't the Ruby Way, so I'm looking at turning it into a  
module (a topic for another message).

Originally, I was curious how to refactor my classes (and tests). I  
decided to write a second concrete subclass to see what kind of  
problems I might run into. I figured *any* problem I encountered was  
just more information for me to figure out the correct direction. The  
second subclass started out normally enough. I spec'd some behavior  
unique to that subclass. So far, so good. Then it occurred to me that  
I had no idea if the parent class was really being exercised by my new  
tests; turns out it wasn't being exercised.

To resolve this I started adding some tests to make sure I covered the  
original behavior of the parent class. Now I had code duplication. The  
parent class tests and my *first* subclass were duping some of the  
same behavior. Looking into the examples directory I saw the concept  
of #shared_examples_for.

I refactored my tests using shared examples. Most of these went into  
the parent class (perhaps soon to be a module). All the tests in my  
subclasses then focused exclusively on the behavior unique to that  
specific class while the describe blocks called #it_should_behave_like  
for shared behaviors. This DRY'ed the code up considerably.

An added benefit was some test breakage I ran across while refactoring  
the tests. My second subclass had some rather tight coupling to the  
tests, so when I made it shared the subclass test broke. It forced me  
to rethink some of the test and class design to loosen the coupling.  
Ultimately it led to a better class api.

So, that's my rambling summary. Kudos to you if you read this far.

My next goal is to DRY up some of my 'before (:each)' blocks. I  
continually do the same setup operations across #describe blocks (@buf  
= Buf.new; @msg = blah, etc). It looks like I may want to define  
subclasses of a parent Spec::ExampleGroup so the subclasses can  
inherit some of the #before setup. I'd love to hear experiences from  
others on this technique.

Lastly, I thought I'd say a word on the resulting class code. This BDD  
project was a learning experience. I rewrote a set of classes that I  
had originally written the old-fashioned way; puzzle through the logic  
in my head, write the code, and then debug the crap out of it until it  
worked. The original classes are rather short (LOC) with only a few  
methods (3 or 4). The classes I wrote via BDD are longer, maybe by 40%  
in terms of LOC. Plus, I now have around 10 methods none of which  
exceeds 5 lines of "real" code. It's more readable, more logical, and  
*far* easier to subclass. I'm now a believer.

YMMV.

cr


___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users


Re: [rspec-users] [Q] how to restructure tests for an abstract class?

2008-02-25 Thread David Chelimsky
On Mon, Feb 25, 2008 at 6:23 AM, Chuck Remes <[EMAIL PROTECTED]> wrote:
> Thanks for asking this question. This is exactly what I was going to write,
> but you beat me to it!
>
> (Sorry for the top-post; just following the last responder.)
>
> cr
>
>
>
> On Feb 25, 2008, at 3:30 AM, Matthijs Langenberg wrote:
> Question is, would you duplicate the specs for all the classes that include
> a certain module (through shared behaviour for example), or would you use
> one set of specs for just the module, and specify that a class should
> include that module?

Matthijs - I'd throw the same question back to you. Have you tried
both approaches? How have they worked out for you?

I won't wait for your answer :). But I am curious about other people's
experiences with this.

I can tell you this from my own experience - I tend to use shared
groups for this for a couple of reasons. One, I like to see the specs
for each object. Seeing this 

Thing
- should include the Foo module

in the spec output doesn't really help me understand what Thing does.

Keep in mind that including a module does not guarantee that the
methods in that module are used. They can be redefined. They can also
behave differently depending on the state of the including object. For
these reasons, I generally don't really like to specify module
inclusion.

I try to approach this from the perspective of "how do I want
instances of this type to behave?" When I find duplication in
behaviour across types, I may extract a shared example group.

The discipline challenge really comes in when I already have a shared
group and I'm adding a new type and my inner designer is quite certain
that it should include the same module. I can tell you that I've gone
at this from two directions - either spec'ing the new type cold or
just including the shared group in the spec for the type and including
the module. Neither route has been perfect every time :)

Hope that helps ... a little.

Cheers,
David


>
> On Sun, Feb 24, 2008 at 12:19 AM, Pat Maddox <[EMAIL PROTECTED]> wrote:
> >
> >
> >
> > On Thu, Feb 21, 2008 at 8:09 AM, Chuck Remes <[EMAIL PROTECTED]>
> wrote:
> > > While practicing BDD on my first-ever BDD project, I have come to a
> > >  point where it makes sense to change my original class to an abstract
> > >  class and create one (or more) concrete subclasses that implement a
> > >  specific method. What is the right way to restructure the tests in
> > >  this scenario? Do I leave the existing tests in place and just create
> > >  a new spec file that instantiates and tests the concrete subclass?
> > >
> > >  I think I can continue to instantiate my "abstract" parent as long as
> > >  I don't go near the behavior that will be defined by the concrete
> > >  subclasses. Is that the right thing to do?
> > >
> > >  Thanks for any hints.
> > >
> > >  cr
> > >  ___
> > >  rspec-users mailing list
> > >  rspec-users@rubyforge.org
> > >  http://rubyforge.org/mailman/listinfo/rspec-users
> > >
> >
> > I think that shared example groups might be useful.
> >
> > Pat
> >
> >
> >
> > ___
> > rspec-users mailing list
> > rspec-users@rubyforge.org
> > http://rubyforge.org/mailman/listinfo/rspec-users
> >
>
>  ___
> rspec-users mailing list
> rspec-users@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
> ___
>  rspec-users mailing list
>  rspec-users@rubyforge.org
>  http://rubyforge.org/mailman/listinfo/rspec-users
>
___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users


Re: [rspec-users] [Q] how to restructure tests for an abstract class?

2008-02-25 Thread Chuck Remes
Thanks for asking this question. This is exactly what I was going to  
write, but you beat me to it!


(Sorry for the top-post; just following the last responder.)

cr

On Feb 25, 2008, at 3:30 AM, Matthijs Langenberg wrote:

Question is, would you duplicate the specs for all the classes that  
include a certain module (through shared behaviour for example), or  
would you use one set of specs for just the module, and specify that  
a class should include that module?


On Sun, Feb 24, 2008 at 12:19 AM, Pat Maddox <[EMAIL PROTECTED]>  
wrote:
On Thu, Feb 21, 2008 at 8:09 AM, Chuck Remes  
<[EMAIL PROTECTED]> wrote:

> While practicing BDD on my first-ever BDD project, I have come to a
>  point where it makes sense to change my original class to an  
abstract

>  class and create one (or more) concrete subclasses that implement a
>  specific method. What is the right way to restructure the tests in
>  this scenario? Do I leave the existing tests in place and just  
create

>  a new spec file that instantiates and tests the concrete subclass?
>
>  I think I can continue to instantiate my "abstract" parent as  
long as

>  I don't go near the behavior that will be defined by the concrete
>  subclasses. Is that the right thing to do?
>
>  Thanks for any hints.
>
>  cr
>  ___
>  rspec-users mailing list
>  rspec-users@rubyforge.org
>  http://rubyforge.org/mailman/listinfo/rspec-users
>

I think that shared example groups might be useful.

Pat
___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users


___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Re: [rspec-users] [Q] how to restructure tests for an abstract class?

2008-02-25 Thread Matthijs Langenberg
Question is, would you duplicate the specs for all the classes that include
a certain module (through shared behaviour for example), or would you use
one set of specs for just the module, and specify that a class should
include that module?

On Sun, Feb 24, 2008 at 12:19 AM, Pat Maddox <[EMAIL PROTECTED]> wrote:

> On Thu, Feb 21, 2008 at 8:09 AM, Chuck Remes <[EMAIL PROTECTED]>
> wrote:
> > While practicing BDD on my first-ever BDD project, I have come to a
> >  point where it makes sense to change my original class to an abstract
> >  class and create one (or more) concrete subclasses that implement a
> >  specific method. What is the right way to restructure the tests in
> >  this scenario? Do I leave the existing tests in place and just create
> >  a new spec file that instantiates and tests the concrete subclass?
> >
> >  I think I can continue to instantiate my "abstract" parent as long as
> >  I don't go near the behavior that will be defined by the concrete
> >  subclasses. Is that the right thing to do?
> >
> >  Thanks for any hints.
> >
> >  cr
> >  ___
> >  rspec-users mailing list
> >  rspec-users@rubyforge.org
> >  http://rubyforge.org/mailman/listinfo/rspec-users
> >
>
> I think that shared example groups might be useful.
>
> Pat
> ___
> rspec-users mailing list
> rspec-users@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Re: [rspec-users] [Q] how to restructure tests for an abstract class?

2008-02-23 Thread Pat Maddox
On Thu, Feb 21, 2008 at 8:09 AM, Chuck Remes <[EMAIL PROTECTED]> wrote:
> While practicing BDD on my first-ever BDD project, I have come to a
>  point where it makes sense to change my original class to an abstract
>  class and create one (or more) concrete subclasses that implement a
>  specific method. What is the right way to restructure the tests in
>  this scenario? Do I leave the existing tests in place and just create
>  a new spec file that instantiates and tests the concrete subclass?
>
>  I think I can continue to instantiate my "abstract" parent as long as
>  I don't go near the behavior that will be defined by the concrete
>  subclasses. Is that the right thing to do?
>
>  Thanks for any hints.
>
>  cr
>  ___
>  rspec-users mailing list
>  rspec-users@rubyforge.org
>  http://rubyforge.org/mailman/listinfo/rspec-users
>

I think that shared example groups might be useful.

Pat
___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users


Re: [rspec-users] [Q] how to restructure tests for an abstract class?

2008-02-21 Thread Rick DeNatale
On 2/21/08, Chuck Remes <[EMAIL PROTECTED]> wrote:
> While practicing BDD on my first-ever BDD project, I have come to a
>  point where it makes sense to change my original class to an abstract
>  class and create one (or more) concrete subclasses that implement a
>  specific method. What is the right way to restructure the tests in
>  this scenario? Do I leave the existing tests in place and just create
>  a new spec file that instantiates and tests the concrete subclass?
>
>  I think I can continue to instantiate my "abstract" parent as long as
>  I don't go near the behavior that will be defined by the concrete
>  subclasses. Is that the right thing to do?

Let me respond not so much from a BDD/RSpec point of view, but from a
Ruby language perspective.

Abstract classes aren't used much in Ruby, most often the job of
providing "abstract" methods is done by modules rather than classes.

Abstract classes are used in languages which define types via
inheritance like C++ or Java , or provide only single inheritance of
implementation like Smalltalk.

In C++/Java you're pretty much forced to use an abstract class if you
want to provide partial implementation of a type to be filled out by
subclasses.  In Smalltalk they're used to keep things DRY.

In Smalltalk, there are quite a few abstract classes, for example
Collection provides an implementation of methods like select, map,
inject based on subclasses implementing an each method.  In Ruby the
same thing is done by having the Enumerable module which can be mixed
into classes which provide an each method.

So the way I'd approach the kind of refactoring you seem to be
implying would be to move the abstract methods in the existing class
into a module included by that class, and then implement other classes
which also include the module.

HTH

-- 
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
___
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users