This article will show how to “test drive” the prime factors kata in Ruby with RSpec, a spec style unit testing framework.

For an explanation of Test-Driven Development (TDD) itself, see this article.

Problem: We want to factor a number into it’s base primes. For example 9 can be factored into 3x3 and 20 can be factored into 2x2x5.

The first stage in TDD is **red** where we create a failing test. It’s important to remember that we don’t want to write any production code until that’s the only way we can make a test pass.

### First test: factor 2

For our first test, we’ll attempt to factor 2, which should result in an array containing only two.

```
describe PrimeFactors do
it 'should return 2 for 2' do
expect(PrimeFactors.factor(2)).to eql([2])
end
end
```

Initially, this won’t even compile so it isn’t failing for the right reason.

```
NameError:
uninitialized constant PrimeFactors
```

We write enough code to allow it to compile and run.

```
class PrimeFactors
def self.factor(number)
[]
end
end
```

We verify that the test is still failing, now for the right reason.

```
expected: [2]
got: []
```

Next we move to **green**, where we need to make the test pass. We’re not looking to make the code beautiful or performance or reusable at this point. We’re looking to make the test pass in the easiest possible way.

```
defmodule PrimeFactors do
def factor(number) do
[2]
end
end
```

We know that hard coding the 2 at this point is silly and that it’s going to cause problems later but we don’t care. The TDD process will get us there at the right time. For now, we only care about the one case that we’ve written a test for.

Now we come to the third stage in the process, **refactor**. We look at the code and the tests and we look to see if there’s anything we might want to improve. There usually isn’t for the first test but there certainly will be things to improve once we have a couple of tests and we want to explicitly ask ourselves at this point.

### Second test: factor 3

We already recognized that hard coding the 2 was bad so let’s create another test that forces us to fix that. We’re back in **red**

```
it 'should return 3 for 3' do
expect(PrimeFactors.factor(3)).to eql([3])
end
```

We run the test and it fails for the right reason.

```
expected: [3]
got: [2]
```

We satisfied red and now move on to **green**. Change the production code to make the test pass. The simplest thing that could work.

```
class PrimeFactors
def self.factor(number)
[number]
end
end
```

Now both tests are passing so we consider the **refactor** step. Is there any duplication? Anything we might want to improve at this point? I’m thinking no, so we’ll move on.

### Third test: factor 4 (two times a prime)

**red**: The test for 4 is straight forward. We should get back two and two.

```
it 'should return 2,2 for 4' do
expect(PrimeFactors.factor(4)).to eql([2, 2])
end
```

**green**: The implementation is more complex here because for the first time, we have a chance to actually calculate something instead of just hard coding.

I notice that any even number can be divided by 2 so check if it’s even and then split into 2 and whatever is left.

```
class PrimeFactors
def self.factor(number)
result = []
if (number % 2).zero?
result << 2
number /= 2
end
result << number
result
end
end
```

When the tests are run again, we discover that while the test for 4 (the immediate concern) is passing, one of our earlier tests is now failing. Specifically the test for 2 which is now returning [2,1]

We’re still in the **green** phase so we want the simplest solution that gets us working again. We’ll add a special case for 2.

```
class PrimeFactors
def self.factor(number)
result = []
if (number % 2).zero? && number != 2
result << 2
number /= 2
end
result << number
result
end
end
```

All tests are passing so we move on to **refactor**. I’m really not liking all the hard coded 2’s but I’m not sure how I want to handle that yet so I’ll defer fixing it. It’s likely now that we’ll work for two times any prime but we may not work for powers of two times a prime. Let’s test-drive that.

### Fourth test: factor 8 (power of two times a prime)

**red**: Create a test for 8 and watch it fail.

```
it 'should return 2,2,2 for 8' do
expect(PrimeFactors.factor(8)).to eql([2, 2, 2])
end
```

**green**: We really just want to execute that if condition multiple times so what if we change the *if* to a *while*?

```
class PrimeFactors
def self.factor(number)
result = []
while (number % 2).zero? && number != 2
result << 2
number /= 2
end
result << number
result
end
end
```

Now it looks like we’ve handled all powers of two times a prime.

**refactor**: Back to the refactor step, and I’m increasingly unhappy with all the hard coded 2’s so let’s deal with that now.

```
class PrimeFactors
def self.factor(number)
result = []
divisor = 2
while (number % divisor).zero? && number != divisor
result << divisor
number /= divisor
end
result << number
result
end
end
```

All we’ve really done is make a constant so 2 is still hard coded. It’s only in one place now, however, which makes the code feel much cleaner to me.

All tests continue to pass so we move on.

### Fifth test: factor 9 (power of two times a prime)

**red**: We know that powers of two are all working and it feels pretty obvious that it’s going to break when we attempt multiple of 3 so let’s start there. Next test is for 3x3

```
it 'should return 3,3 for 9' do
expect(PrimeFactors.factor(9)).to eql([3, 3])
end
```

Test fails, and for the right reason.

```
expected: [3, 3]
got: [9]
```

**green**: For the case of 9, we really want to execute the whole *while* for both 2 and 3 so what if we did a loop within a loop?

```
class PrimeFactors
def self.factor(number)
result = []
(2..3).each do |divisor|
while (number % divisor).zero? && number != divisor
result << divisor
number /= divisor
end
end
result << number
result
end
end
```

All tests continue to pass.

**refactor**: The code and the tests are both looking pretty clean so nothing I want to change. We still always need to stop and reflect at this point though.

### Sixth test: factor 25

If we think our way through all the numbers as we go up, we can see that we’ve handled every power of two times and prime and every power of three times a prime but we don’t handle fives.

**red**: So let’s test for 25.

```
it 'should return 5,5 for 25' do
expect(PrimeFactors.factor(25)).to eql([5, 5])
end
```

**green**: The simplest possible thing to make the test pass would be to increase the range to 5.

```
class PrimeFactors
def self.factor(number)
result = []
(2..3).each do |divisor|
while (number % divisor).zero? && number != divisor
result << divisor
number /= divisor
end
end
result << number
result
end
end
```

All tests continue to pass. Now I wonder, if we were able to make it work by only changing the range, could I make the range large enough right now to solve for every possible case? We know the divisor can’t be larger than the original number passed in so let’s set the high end of the range to that.

```
class PrimeFactors
def self.factor(number)
result = []
(2..number).each do |divisor|
while (number % divisor).zero? && number != divisor
result << divisor
number /= divisor
end
end
result << number
result
end
end
```

Everything continues to pass.

At this point, I think we’ve handled every possible case. We might want to spot-check some larger numbers to see if we can uncover something that we didn’t handle, but that’s more **exploratory testing** and not **test-driven development** so we’ll stop here.

### Recap

We took one step at a time to solve the problem. We created one tiny test and watched it fail (**red**), we did the simplest thing to make it pass (**green**), and we looked for opportunities to make it better (**refactor**). Then we did it again, and again, until we’d finished the feature.