Varying test data

This isn’t specific to RSpec, but is hopefully on-topic for this list.

I like (especially when “ping pong pairing”) to write a spec, then
write the smallest amount of code I can to pass it (especially when
“ping pong pairing”). Sometimes this means hard-coding a return value,
which means another spec is needed to prove that the code is really
behaving as it should. Trivial example:


describe Adder do
it “should add two numbers” do
Adder.add(2, 2).should == 4
end
end

class Adder
def add a, b
4
end
end

describe Adder do
it “should add 2 and 2” do
Adder.add(2, 2).should == 4
end
it “should add 3 and 4” do
Adder.add(3, 4).should == 7
end
end

class Adder
def add a, b
a + b
end
end

It doesn’t seem right though to have all those duplicate specs. An
alternative is to generate random test data, but I’m not really
comfortable doing that because it means the tests aren’t strictly
repeatable. I guess this is more of a problem with classic state-based
testing, but even using BDD you still have to test state at the leaf
nodes.

Does anyone have an opinion about whether this is a problem, and
whether there’s a clean way of dealing with it?

Thanks,

Kerry

On Jan 11, 2008 2:33 AM, Kerry B. [email protected] wrote:

it “should add two numbers” do
describe Adder do
a + b

Does anyone have an opinion about whether this is a problem, and
whether there’s a clean way of dealing with it?

If I were your pair, I would smack you if you hard-coded 4 and moved
on to the next test :slight_smile: You forgot the third step in BDD -
refactoring! At the simplest level, that means removing duplication.
The duplication in this case is between the test and production code.
In your adder example, the red/green/refactor cycle ought to go like:

red - write the spec
green - make it pass by returning 4
refactor - generalize the method by returning the sum of the two
variables

Okay, I wouldn’t smack you necessarily. What you’re describing here
is a TDD technique called Triangulation. Basically you keep writing
tests until you have enough info to drive a useful generalization.

With such a simple example, Triangulation probably isn’t necessary.
You can use Obvious Implementation (where you would just type out a +
b to begin with - after being red first, of course), or you Fake It
(by first returning 4 to get to green, then generalizing).

Specs should give you confidence that the code works as expected. If
it takes you two specs to Triangulate on a solution, and the two specs
are redundant, feel free to delete one of them. Delete a spec if it
doesn’t add value, and keep it around if deleting it would reduce your
confidence.

I recommend reading Kent Beck’s “TDD By Example” for a more in-depth
discussion of these (and plenty other) techniques.

Pat

On Jan 11, 2008 4:33 AM, Kerry B. [email protected] wrote:

it “should add two numbers” do
describe Adder do
a + b

Does anyone have an opinion about whether this is a problem, and
whether there’s a clean way of dealing with it?

The approach you are taking (writing the second example) is called
triangulation. An other approach is to recognize in the first example
that there is duplication between the example and the code being
described. In this case, the number 4. From a duplication-removing
perspective, that is sufficient motivation to make the change during
the refactoring phase in THIS particular example.

If you were describing an object that behaved fundamentally
differently depending on input values, then you’d want the different
examples. In this case, returning the sum is not fundamentally
different in my view.

That said, if you were REALLY building a calculator and not relying on
the addition facilities of the language you were using, you would
naturally have additional examples to cover edge cases. Double digits,
for example.

You might also want to run this by the testdrivendevelopment list
(http://tech.groups.yahoo.com/group/testdrivendevelopment/).

Cheers,
David

On Jan 11, 2008 11:33 AM, Kerry B. [email protected] wrote:

it “should add two numbers” do
describe Adder do
a + b

It may not be applicable in your trivial context, but “pair-wise”
testing (has nothing to do with pair programming) is a really powerful
technique you could consider. It’s a mini method that generates input
combinations based on a set of possible values, dramatically reducing
the number of combinations while still giving you the most important
combinations.

It’s based on a theory that bugs often occur when a pair of data
changes, and it tries to generate data that covers as many pairs as
possible without going overboard.

It’s the most interesting test-related practice I have learned in
several years (there are separate conferences on the topic!). I
haven’t tried it myself, but I know several colleagues who’ve had
great success with it. There is also a tool (perl script) you can use
to generate input values for you (you figure out the expected results
yourself - it doesn’t do that for you). And best of all - it looks
really easy to use, both as a technique and a tool.

http://www.testingeducation.org/wtst5/PairwisePNSQC2004.pdf

http://www.developsense.com/2007/11/pairwise-testing.html
http://www.developsense.com/testing/PairwiseTesting.html

Aslak

On Jan 11, 2008 2:50 AM, David C. [email protected] wrote:

behaving as it should. Trivial example:
4
end
comfortable doing that because it means the tests aren’t strictly
The duplication in this case is between the test and production code.
With such a simple example, Triangulation probably isn’t necessary.
I recommend reading Kent Beck’s “TDD By Example” for a more in-depth
discussion of these (and plenty other) techniques.

Apparently, Pat and I are twins separated at birth.

Have I ever told you what a smart guy you are? :slight_smile:

On 11 Jan 2008, at 10:50, David C. wrote:

On Jan 11, 2008 4:48 AM, Pat M. [email protected] wrote:

Apparently, Pat and I are twins separated at birth.

Thanks both!

Kerry

We’re clearly at green!

Nathan S.
[email protected]
rspec 1.1
rspec_on_rails 1.1
rails 2.0.2

On Jan 11, 2008, at 5:50 AM, David C. wrote:

Apparently, Pat and I are twins separated at birth.

Would it then be correct to refactor and eliminate one of them??

:))

On Jan 11, 2008 10:19 AM, Jonathan L. [email protected]
wrote:

On Jan 11, 2008, at 5:50 AM, David C. wrote:

Apparently, Pat and I are twins separated at birth.

Would it then be correct to refactor and eliminate one of them??

If you could argue that we were ultimately composed of 1s and 0s,
perhaps.