Fibonacci TDD Kata in Golang — from Zero to Hero in less than 5 minutes

A quick walk-through on implementing Fibonacci with Golang using TDD.

Feb 15 · 4 min read

The main assumption here is that you do have a GO environment working and you know something about TDD. If that is not the case, you may need to set-up your environment, read or watch videos about TDD.

I will be using the ginkgo test library. It has an easy setup, and allows for quite a small amount of test code required for each test case. At a later stage (beyond the scope of this post) it would also allow for switching gears and moving into BDD.

Let’s get ready!

1. Go get dependencies

There are 3 dependencies required for this post. Ginkgo, the testing framework. Table extension, which allows for a table-like approach, creating test cases based in entries of inputs vs expected outputs. And Gomega, a matcher library.

go get github.com/onsi/ginkgo/ginkgo
go get github.com/onsi/ginkgo/extensions/table
go get github.com/onsi/gomega/...

2. Boilerplating

Now we can use ginkgo to create our test suite and generate our first test file:

ginkgo bootstrap
ginkgo generate fibonacci

Open the test file. Add the import for the table extensions and the create the boilerplate code for the test:

Create a new file to contain our production code, and name itfibonacci.go. Its contents initially would look like this:

That’s it, you now should be ready to start writing some tests!

Red, Green, Refactor!

From this point the goal is to write a test, run it, get a red light and then write just enough production code to make it pass. Remembering that compilation errors are to be treated as test failures — at this point our code is not compiling as the Fib function does not exist. :)

Baby Steps

Keep it real simple. I mean, really. An useful approach to get into this mindset is to use the Transformation Priority Premise. This helps you stop trying to jump into conclusions or writing production code for which you don’t have tests.

First Test

The first test case could be to ensure that Fibonacci of 0 is 0:

Entry("fib(0)", 0, 0),

This test case needs to be inside of DescribeTable. The entire test file at this point would look like this:

Running the tests (go test) would lead to a compilation error:

/fibonacci_test.go:16:20: fibonacci.Fib undefined (type fibonacci.Fibonacci has no field or method Fib)
FAIL github.com/pjbgf/golang-fibonacci [build failed]

To make it pass, we create a very simple Fib function in the production code:

func (f Fibonacci) Fib(steps int) (result int) {
return
}

Running the tests again we get a pass:

Running Suite: GolangFibonacci Suite
====================================
Random Seed: 1550219992
Will run 1 of 1 specs

Ran 1 of 1 Specs in 0.002 seconds
SUCCESS! -- 1 Passed | 0 Failed | 0 Pending | 0 Skipped
PASS
ok github.com/pjbgf/golang-fibonacci 0.022s

Switching Gears

Carrying on through baby steps through the different test cases, you will potentially arrive at this:

Entry("fib(0)", 0, 0),
Entry("fib(1)", 1, 1),
Entry("fib(2)", 2, 1),
Entry("fib(3)", 3, 2),
Entry("fib(4)", 4, 3),
Entry("fib(5)", 5, 5),

And a production code:

func (f Fibonacci) Fib(steps int) (result int) {
if steps == 1 || steps == 2 {
result = 1
} else if steps == 3 {
result = 2
} else if steps == 4 {
result = 3
} else if steps == 5{
result = 5
}
}

Around here, it will become clear that for cases beyond 2, result tends to be the sum of the last two steps. So, provided that all tests are currently passing, you could refactor the code above into:

func (f Fibonacci) Fib(steps int) (result int) {
if steps == 1 || steps == 2 {
result = 1
} else if steps == 3 {
result = f.Fib(2) + f.Fib(1)
} else if steps == 4 {
result = f.Fib(3) + f.Fib(2)
} else if steps == 5{
result = f.Fib(4) + f.Fib(3)
}
}

Running the tests again, all should pass. We can take our refactor further and make those recurrent calls to be based on the value of the parameter steps:

func (f Fibonacci) Fib(steps int) (result int) {
if steps == 1 || steps == 2 {
result = 1
} else if steps > 2 {
result = f.Fib(steps-1) + f.Fib(steps-2)
}
}

Remember, only implement new production code when you have a failing test for it. And only refactor when your tests are all passing.

At this point, all tests should still be passing. Any new test case you create should pass right away. So that’s it, Fibonacci in golang done!

Wrapping up…

The idea on this post was to show how to do TDD on golang for people who already do that practice in another languages. If you don’t, I recommend reading more on the subject. :)

I found ginkgo to be quite a useful testing framework, specially when you want to use a table-based approach or want to do BDD. If you know of a better testing framework, I am more than keen to hear about it.

Here’s a short (2m49s) run-through based on the approach above:

Paulo Gomes

Written by

Software craftsman on the eternal learning path towards (hopefully) mastery. Security enthusiast keen on SecDevOps. My opinions are my own.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade