Go FizzBuzz kata

Bjorn Krols

Bjorn Krols

Published on
18 May 2022

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:

InputOutput
11
22
3fizz
44
5buzz
6fizz
77
88
9fizz
10buzz
1111
12fizz
1313
1414
15fizzbuzz

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))
    }
}

Subscribe to our newsletter

The latest news, articles, and resources, sent to your inbox weekly.

More like this