How to make efficient code emerge through unit testing
- by Jean
Hi,
I participate in a TDD Coding Dojo, where we try to practice pure TDD on simple problems. It occured to me however that the code which emerges from the unit tests isn't the most efficient. Now this is fine most of the time, but what if the code usage grows so that efficiency becomes a problem.
I love the way the code emerges from unit testing, but is it possible to make the efficiency property emerge through further tests ?
Here is a trivial example in ruby: prime factorization. I followed a pure TDD approach making the tests pass one after the other validating my original acceptance test (commented at the bottom).
What further steps could I take, if I wanted to make one of the generic prime factorization algorithms emerge ? To reduce the problem domain, let's say I want to get a quadratic sieve implementation ... Now in this precise case I know the "optimal algorithm, but in most cases, the client will simply add a requirement that the feature runs in less than "x" time for a given environment.
require 'shoulda'
require 'lib/prime'
class MathTest < Test::Unit::TestCase
context "The math module" do
should "have a method to get primes" do
assert Math.respond_to? 'primes'
end
end
context "The primes method of Math" do
should "return [] for 0" do
assert_equal [], Math.primes(0)
end
should "return [1] for 1 " do
assert_equal [1], Math.primes(1)
end
should "return [1,2] for 2" do
assert_equal [1,2], Math.primes(2)
end
should "return [1,3] for 3" do
assert_equal [1,3], Math.primes(3)
end
should "return [1,2] for 4" do
assert_equal [1,2,2], Math.primes(4)
end
should "return [1,5] for 5" do
assert_equal [1,5], Math.primes(5)
end
should "return [1,2,3] for 6" do
assert_equal [1,2,3], Math.primes(6)
end
should "return [1,3] for 9" do
assert_equal [1,3,3], Math.primes(9)
end
should "return [1,2,5] for 10" do
assert_equal [1,2,5], Math.primes(10)
end
end
# context "Functionnal Acceptance test 1" do
# context "the prime factors of 14101980 are 1,2,2,3,5,61,3853"do
# should "return [1,2,3,5,61,3853] for ${14101980*14101980}" do
# assert_equal [1,2,2,3,5,61,3853], Math.primes(14101980*14101980)
# end
# end
# end
end
and the naive algorithm I created by this approach
module Math
def self.primes(n)
if n==0
return []
else
primes=[1]
for i in 2..n do
if n%i==0
while(n%i==0)
primes<<i
n=n/i
end
end
end
primes
end
end
end