🧪

【Go】Developer eXperience Day 2021における和田さんのテスト駆動開発の解説をGoで実装してみた

2021/10/23に公開

動画リンク

勉強になったので人類見ましょう

Developer eXperience Day 【Stream A】 テストコードのリファクタリングが目指すもの

実装

productionコード

int_closed_range.go
package main

import "strconv"

type IntClosedRange struct {
	lower int
	upper int
}

func (r IntClosedRange) Lower() int {
	return r.lower
}

func (r IntClosedRange) Upper() int {
	return r.upper
}

func (r IntClosedRange) Notation() string {
	// 文字列と数字の結合はgoでは地道な方法しかなかった
	return "[" + strconv.Itoa(r.lower) + "," + strconv.Itoa(r.upper) + "]"
}

func (r IntClosedRange) Includes(i int) bool {
	return r.lower <= i && i <= r.upper
}

suiteを使って状況>機能という階層整理で書いた

が、整理がちょっと十分でないなとは感じてます。

int_closed_range_test.go
package main

import (
	"github.com/stretchr/testify/suite"
	"testing"
)

type intClosedRangeSuite struct {
	suite.Suite
	icRange IntClosedRange
}

func (suite *intClosedRangeSuite) SetupSuite() {
	suite.icRange = IntClosedRange{3, 7}
}

func (suite *intClosedRangeSuite) Test_整数閉区間は下端点3を持つ() {
	suite.Equal(3, suite.icRange.Lower())
}

func (suite *intClosedRangeSuite) Test_Upperメソッドは上端点7を持つ() {
	suite.Equal(7, suite.icRange.Upper())
}

func (suite *intClosedRangeSuite) Test_Notationメソッドは文字列表記を返せる() {
	suite.Equal("[3,7]", suite.icRange.Notation())
}

func (suite *intClosedRangeSuite) Test_Includesメソッドは指定した整数を含むか判定できる() {
	tests := map[string]struct {
		input    int
		includes bool
	}{
		"9は含まれない":   {9, false},
		"5は含まれる":    {5, true},
		"1は含まれない":   {1, false},
		"下端点3は含まれる": {3, true},
		"上端点7は含まれる": {7, true},
	}

	for name, test := range tests {
		suite.Run(name, func() {
			suite.Equal(test.includes, suite.icRange.Includes(test.input))
		})
	}
}

func Test_整数閉区間を表す(t *testing.T) {
	suite.Run(t, new(intClosedRangeSuite))
}

suiteを使って状況>機能という階層整理で書いたテストケース一覧

機能>状況という階層整理で書いた

int_closed_range_test.go
package main

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func Test_Lowerメソッドは下端点を返せる(t *testing.T) {
	icRange := IntClosedRange{3, 7}
	assert.Equal(t, 3, icRange.Lower())
}

func Test_Upperメソッドは上端点を返せる(t *testing.T) {
	icRange := IntClosedRange{3, 7}
	assert.Equal(t, 7, icRange.Upper())
}

func Test_Notationメソッドは文字列表記を返せる(t *testing.T) {
	icRange := IntClosedRange{3, 7}
	assert.Equal(t, "[3,7]", icRange.Notation())
}

func Test_Includesメソッドは指定した整数を含むか判定できる(t *testing.T) {
	tests := map[string]struct {
		input    int
		includes bool
	}{
		"9は含まれない":   {9, false},
		"5は含まれる":    {5, true},
		"1は含まれない":   {1, false},
		"下端点3は含まれる": {3, true},
		"上端点7は含まれる": {7, true},
	}

	icRange := IntClosedRange{3, 7}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			assert.Equal(t, test.includes, icRange.Includes(test.input))
		})
	}
}

機能>状況という階層整理で書いたテストケース一覧

勉強になったこと・気付き

  • Goも日本語メソッドが使える
  • suiteがあることを初めて知った
  • が、書き方が普段のテストと違うのでちょっと扱いづらいかも
  • Goはtable driven testが推奨されているので、そういう意味でも機能>状況という階層整理が合いそう

実装したリポジトリ

kumackey/eXperienceDayGo

Discussion