Re: [rspec-users] [Q] how to restructure tests for an abstract class?
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?
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?
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?
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?
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?
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