Behavior Driven Development: Inside-Out vs Outside-In Pattern 3
Recently at work we've been having a bit of an argument over the proper way to structure a spec while doing Behavior Driven Development.
I'm going to illustrate a couple of patterns that have emerged using the simple example of a sword that should tell you if it is sharp or not, depending on whether it is new or used.
One camp at my current job, likes to use what I'm calling the Inside-Out Pattern for writing specs. This group likes to start with the method name and then define behavior for it. An example of this is shown here (in RSpec syntax):
describe "sharp?" do
it "should tell you if it is sharp or not" do
Sword.new(:status => 'new').sharp?.should == true
Sword.new(:status => 'used').sharp?.should == false
end
end Their argument for this pattern is that all of the code for that method stays in one place, so it's easy to see if you've covered everything in that method.
The argument against this is that your specs are harder to understand and you can't really do real TDD with this method of development.
The other camp likes to use what I'm calling the Outside-In Pattern. This pattern describes the possible states of the object first, and then describes what the object should do in each state:
describe "A new sword" do
before(:each) do
@sword = Sword.new(:status => 'new')
end
it "should tell us that it is sharp" do
@sword.sharp?.should == true
end
end
describe "A used sword" do
before(:each) do
@sword = Sword.new(:status => 'used')
end
it "should tell us that it is not sharp" do
@sword.sharp?.should == false
end
endThe argument for this pattern is that it is more descriptive of what the object should do and it helps with TDD.
The argument this is that you get too many descriptions in your spec, and they can get hard to read. Also, the behavior for a single method in a class is spread around the multiple descriptions, so it becomes harder to make sure that all of the behavior of your method is covered.
Most of the specs that we've written so far seem to skew towards one or the other of these options, but there's no consensus on which of them is better yet, so I figured I'd throw it out there and see if anyone has experience one way or the other and which one has worked better.
Please let me know in the comments.
(And yes, before anyone asks, I'm firmly in one of the camps, and yes, I purposely didn't reveal which one here. I'll be talking more about it in a later post.)
Update: My coworker Dustin points out another way of doing specs that rests firmly in the middle of these two views.
Trackbacks
Use the following link to trackback from your own site:
http://kurt.karmalab.org/trackbacks?article_id=behavior-driven-development-inside-out-vs-outside-in-patterns&day=04&month=05&year=2007
-
The vanilla example used in most blog posts for BDD is some incarnation of de novo domain object specification, that is, specifying the behavior of a simple domain object from scratch. David Chelimsky’s stack example is a decent online examp...
I definitely prefer outside-in. A couple of justifications:
The context should represent a state, not an object or method. "A sword" is only a context if you're specifying behaviour for all swords, "A new sword" describes a sword in a certain state, and "sharp?" seems to me to be a programmer-centric way of writing specs (more like an early xUnit approach, where we used to generally write one test per method).
I also like to keep to one assertion per test, so the inside-out example would have to be split into "should return true when the sword is new" and "should return false when the sword is used". This is slightly more expressive than your example, but still seems to describe what the code does, rather than how the object behaves. This might not always be a bad thing, but I don't think it's really BDD.
Outside in man. Inside out sounds like after-the-fact testing, missing the point of TDD/BDD.
You can say:
sword.should be_sharp
One of Kurt's mysterious coworkers here. Another problem with the inside-out approach above is the name of the example, "sharp?", which is pretty meaningless when you see it in the HTML output of a bunch of specs. Funny for me to say that, because I was the guy discussing this with Kurt. I'm not sure if I'm in a camp, but if I am, I wouldn't describe the camps in this way.
I tried to write something about the original example that prompted this discussion, but midpost realized that the method in question (
blank?) was only used in one place, in the spec code for a collaborating class, so I thought that was a bad example. So instead I focused on a similar situation in the specification of the behavior of the same class. Hopefully more detail helps clarify things.