Post

TDD in GoLang

✅ Test Function

  • t *testing.T
  • t.Errorf : %q, %s: string, %d: integer, %v: generic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func TestHello(t *testing.T) { //t is pointer to testing.T
	got := Add(1, 2)
	want := 3
	if got != want {
		t.Errorf("expected %d, but got %d", got, want)
	}
}

func TestHello(t *testing.T) {
	t.Run("Subtest1", func(t *testing.T)){
		//test code
	}

	t.Run("Subtest2", func(t *testing.T)){
		//test code
	}
}

✅ ExampleTest

  • simply test Add() function with ExampleAdd()
  • need //Output : 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func ExampleAdd() {
	sum := Add(1, 5)
	fmt.Println(sum)
	// Output: 6 //need comment to execute ExampleAdd
}

func TestAdder(t *testing.T) {
	sum := Add(2, 3)
	expected := 5

	if sum != expected {
		t.Errorf("expected %d, but got %d", expected, sum) //%d print int
	}
}

✅ Benchmark

  • Benchmark gives access to loop function
  • b *testing.B
  • 👍🏻 For loop testing
  • measure how long it takes to loop
1
2
3
4
5
func BenchmarkRepeat(b *testing.B) {
	for b.Loop() {
		Repeat("a", 5)
	}
}

✅ Helper function in test

  • when same code is used in test several times, create a helper function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func TestHello(t *testing.T) {
	t.Run("subtest1", func(t *testing.T) {
		//same code needs to be run
		assertCorrectMessage(t, got, want)
	})

	t.Run("subtest2", func(t *testing.T) {
		//same code needs to be run
		assertCorrectMessage(t, got, want)
	})
}

func assertCorrectMessage(t testing.TB, got, want string) {
	t.Helper() //tell suite this method is a helper
	if got != want {
		t.Errorf("got %q want %q", got, want)
	}
}

✅ Assign helper function to variable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func TestSumAllTails(t *testing.T) {
	checkSums := func(t testing.TB, got, want []int) {
		t.Helper() //helper function
		if !reflect.DeepEqual(got, want) {
			t.Errorf("got %v want %v", got, want)
		}
	}

	t.Run("subtest1", func(t *testing.T) {
		//same code needs to be run
		checkSums(t, got, want)
	})

	t.Run("subtest2", func(t *testing.T) {
		//same code needs to be run
		checkSums(t, got, want)
	})
}

✅ Interface and anonymous struct in TDD

  • If testing same method on several interface, can implement anonymous struct

  • 👎🏻 Before, without anonymous struct
  • rectangle and circle implement shape interface
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func TestArea(t *testing.T) {

	checkArea := func(t testing.TB, shape Shape, want float64) {
		t.Helper()
		got := shape.Area()
		if got != want {
			t.Errorf("got %g want %g", got, want)
		}
	}
	//👎🏻 similar test code for both rectangle, circle
	t.Run("rectangle", func(t *testing.T) {
		rectangle := Rectangle{7.0, 6.0}
		want := 42.0

		checkArea(t, rectangle, want)
	})

	t.Run("circle", func(t *testing.T) {
		circle := Circle{10.0}
		want := 314.1592

		checkArea(t, circle, want)
	})
}
  • 👍🏻 after, with anonymous struct
  • create []struct of shape interface
  • make t.Errorf message helpful
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func TestArea(t *testing.T) {
	areaTests := []struct {
		name  string
		shape Shape
		want  float64
	}{
		{name: "Rectangle", shape: Rectangle{width: 12, height: 6}, want: 72.0},
		{name: "Circle", shape: Circle{diameter: 10}, want: 314.1592},
		{name: "Triangle", shape: Triangle{width: 12, height: 6}, want: 36.0},
	}

	for _, tt := range areaTests {
		got := tt.shape.Area()
		if got != tt.want {
			t.Errorf("%v got %g want %g", tt.name, got, tt.want) //Rectangle got 6 want 72
		}
	}
}

This post is licensed under CC BY 4.0 by the author.