In this article, you will learn how to quickly set up a test-driven environment to perform a FizzBuzz kata in Go.
The rules of this kata are:
Return integers 1 to N, but return "fizz" if an integer is divisible by 3, "buzz" if an integer is divisible by 5, and "fizbuzz" if an integer is divisible by both 3 and 5.
Example inputs and outputs:
Input | Output |
---|---|
1 | 1 |
2 | 2 |
3 | fizz |
4 | 4 |
5 | buzz |
6 | fizz |
7 | 7 |
8 | 8 |
9 | fizz |
10 | buzz |
11 | 11 |
12 | fizz |
13 | 13 |
14 | 14 |
15 | fizzbuzz |
Project setup
Create a new Go module:
go mod init kata
Create the main source file:
touch main.go
package main
func FizzBuzz() {
// TODO: add implementation here
}
TDD setup
Install Testify:
go get github.com/stretchr/testify
Create the test file:
touch main_test.go
package main
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestFizzBuzz(t *testing.T) {
// TODO: add tests here
assert.Equal(t, 2, 1+1)
}
To run tests automatically when source files are changed:
watchman-make -p '**/*.go' --make=go -t test
To run tests manually:
go test
Example tests and implementations
Return integers 1 to N
Test:
func TestFizzBuzz(t *testing.T) {
// Return integers 1 to N
assert.Equal(t, "1", FizzBuzz(1))
assert.Equal(t, "2", FizzBuzz(2))
}
Implementation:
func FizzBuzz(n int) string {
return strconv.Itoa(n)
}
Return "fizz" if an integer is divisible by 3
Test:
func TestFizzBuzz(t *testing.T) {
// Return "fizz" if an integer is divisible by 3
assert.Equal(t, "fizz", FizzBuzz(3))
assert.Equal(t, "fizz", FizzBuzz(6))
}
Implementation:
func FizzBuzz(n int) string {
if n%3 == 0 {
return "fizz"
}
return strconv.Itoa(n)
}
Return "buzz" if an integer is divisible by 5
Test:
func TestFizzBuzz(t *testing.T) {
// Return "buzz" if an integer is divisible by 5
assert.Equal(t, "buzz", FizzBuzz(5))
assert.Equal(t, "buzz", FizzBuzz(10))
}
Implementation:
func FizzBuzz(n int) string {
if n%3 == 0 {
return "fizz"
}
if n%5 == 0 {
return "buzz"
}
return strconv.Itoa(n)
}
Return "fizbuzz" if an integer is divisible by both 3 and 5
Test:
func TestFizzBuzz(t *testing.T) {
// Return "fizbuzz" if an integer is divisible by both 3 and 5
assert.Equal(t, "fizzbuzz", FizzBuzz(15))
assert.Equal(t, "fizzbuzz", FizzBuzz(30))
}
Implementation:
func FizzBuzz(n int) string {
result := ""
if n%3 == 0 {
result += "fizz"
}
if n%5 == 0 {
result += "buzz"
}
if result == "" {
result = strconv.Itoa(n)
}
return result
}
All tests are green, you can now refactor at your leisure, here is one example:
package main
import "strconv"
func getWordForMultiple(n int, factor int, word string) string {
if n%factor == 0 {
return word
}
return ""
}
func FizzBuzz(n int) string {
result := ""
result += getWordForMultiple(n, 3, "fizz")
result += getWordForMultiple(n, 5, "buzz")
if result == "" {
result = strconv.Itoa(n)
}
return result
}
Exhaustive test
If you'd like to test your implementation against an exhaustive list of input and output values:
func TestFizzBuzz(t *testing.T) {
results := map[int]string{
1: "1",
2: "2",
3: "fizz",
4: "4",
5: "buzz",
6: "fizz",
7: "7",
8: "8",
9: "fizz",
10: "buzz",
11: "11",
12: "fizz",
13: "13",
14: "14",
15: "fizzbuzz",
}
for input, output := range results {
assert.Equal(t, output, FizzBuzz(input))
}
}