Posted at

golangで始めるTDD


【この記事の目的】

golang x TDDは「あ、こんな風にやればええんやな」という感覚を掴んでもらう為の記事です。


【対象とする人】


  • golangこれから学ぶぞ

  • golangちょっとだけしってる

  • テストコードってどう書けばいいんだろう

  • TDDやったことない

という人を対象としてます


【やってみよう】


< golang基礎編 >


□ Hello World

言語学習の事始めと言ったらやっぱり「Hello World」ですよね!

golangでも例にもれず、まずはHello Worldでどんな感じなのかを確認することができます。

ご存知の方も多いとお思いますが、環境準備をしなくてもPlaygroundで試すことができるので

簡単な挙動の確認くらいだったら検証できます。

早速Playgroundに行って、「Hello World」を実行してみましょう!


hello.go

package main

import "fmt"

func main() {
fmt.Println("Hello, 世界")
}



□ 環境準備

まずはgoのコードを入れましょう。

↓の公式サイトにアクセスをしてβ版ではない最新のバージョンをダウンロードしてセットアップします。

https://golang.org/dl/

golangをセットアップし終わったら、次は「エディタ」を準備します。

個人的なオススメは「VS Code」です。

https://code.visualstudio.com/

軽量かつ様々なプラグインがあるので、デバッグがしやすく扱いやすいです。

今回はこの「VS Code」と「プラグイン」を用いることを前提で話を進めていきます。

プラグインは↓の2つをインストールします。

プラグイン1: Go

用途:vs codeのgolangサポート

プラグイン2: Go Text Explorer

用途:テストに利用


□ 基礎構文

環境も準備できたので、あとは実際に手を動かすばかりではありますが、その前にgolangの基本構文を理解しましょう。

公式に動かして理解する素晴らしい資料があるので、ここでは割愛します。

https://go-tour-jp.appspot.com/welcome/1


□ golangでのテストコード

ここでは詳しいgo testの仕様などは説明しませんが、

とりあえずテストコードが書けるように↓の3つだけざっくりと説明したいと思います。


  • ファイルの名前は「xxx_test.go」で対応させtestingパッケージを利用する

  • 標準関数で評価は十分できる

  • Table Driven Testが推奨されている

※ go testの詳しい概要については↓のような素晴らしい記事を参考にしてください。

https://golang.org/pkg/testing/

https://budougumi0617.github.io/2018/08/19/go-testing2018/

https://swet.dena.com/entry/2018/01/16/211035


ファイルの名前は「xxx_test.go」で対応させtestingパッケージを利用する

大原則となりますが、テストコードを記述するファイルは xxx_test.go という(xxxはテスト対象のコードがあるファイル名が一般的)名前をつけなくてはなりません。

この名前にすることで「go test」を実行する時にテストコードとして認識してくれます。

xxxはテスト対象のコードがあるファイル名と関係ないものでも動きますが、同じ名前をつけるのが一般的なので敢えて変える必要はないかと思います。


buildOK.sh

$ ls

main.go main_test.go

$ go test
PASS
ok _/home/debug/test 0.007s

$ go build
$ ls
main.go main_test.go test



buildNG.sh

$ ls

aaa.go main.go

$ go test
? _/home/debug/test [no test files]

$ go build
$ ls
aaa.go main.go test


また、テストを実行するのに「 testing 」というパッケージを利用します。

テストを実行して色々確認したりするのに便利なメソッドがまとまってますので、どんなことができるかはReferenceを確認しておくとよいでしょう。

ちなみにtestingパッケージを使う場合は他にも注意点があります。

テストとして実行するメソッドは必ず TestXxx という命名規則で書かなくてはなりません。

なので記述するとしたらこんな感じになります。

※ Test以降の文字列もキャメルケースである必要があります


example.go

package main

import (
"testing"
)

func TestXxx(t *testing.T) {
...
}



標準関数で評価は十分できる

javaなどではassert()を利用して、期待との評価を行うのが一般的かと思いますが

golangでは以下のように評価するケースが多いです。

assert()を利用しなくても十分評価できるので、goに入ってはgoに従えということでこの形式でテストは評価します。

https://play.golang.org/p/jUjXNAsmkxD


plus_test.go

package main

import (
"testing"
)

func Plus(x, y int) int {
return x + y
}

func TestPlus(t *testing.T) {
x, y := 1, 1
expectation := 3

res := Plus(x, y)
if res != expectation {
t.Errorf("Not equal value %v", res)
}
}


↑を実行するとこんな結果が得られます。

どこで失敗したかなどわかりやすいですね。

=== RUN   TestPlus

--- FAIL: TestPlus (0.00s)
prog.go:17: Not equal value 2
FAIL


Table Driven Testが推奨されている

すごくざっくりいうと、「 テストケースをJSONっぽい見た目のテーブルで書くとわかりやすくない? 」という感じの書き方です。

ちゃんとした説明や詳しい内容は参考資料や公式を見てください。

ここではざっくりこんな感じの書き方をするんだなーというところだけ掴んでくれればいいので、実例を載せます。

https://play.golang.org/p/sc7HkbaxA4D


plus_test.go

package main

import (
"testing"
)

func Plus(x, y int) int {
return x + y
}

func TestPlus(t *testing.T) {
data := map[string]struct {
X int
Y int
Expectation int
}{
"正の整数+正の整数": {
X: 1,
Y: 1,
Expectation: 2,
},
"正の整数+負の整数": {
X: 1,
Y: -1,
Expectation: 0,
},
}

for name, d := range data {
t.Run(name, func(t *testing.T) {
res := Plus(d.X, d.Y)
if res != d.Expectation {
t.Errorf("Not equal value %v", res)
}
})
}

}


↑を実行するとこんな結果が得られます。

=== RUN   TestPlus

=== RUN TestPlus/正の整数+正の整数
=== RUN TestPlus/正の整数+負の整数
--- PASS: TestPlus (0.00s)
--- PASS: TestPlus/正の整数+正の整数 (0.00s)
--- PASS: TestPlus/正の整数+負の整数 (0.00s)
PASS

さらっとサブテストの実行までやってしまってますが、この書き方をするとどのケースでどういうデータがセットされているかがひと目でわかりやすいので複数ケースを行う場合はおすすめです。


< TDD基礎編 >


□ TDDの基本

さて、ようやくこれでTDDに入っていきます。

TDDも色々わかりやすい説明をしている記事やt_wadaさんというTDDの現人神のような方がいらっしゃるので、詳しくはそちらを見てください。

なので、ここではほんとに入り口だけを紹介します。

TDDは「 まずは作ろう! 」ではなく「 これはどんなことができる子かな? 」という完成品が叶えるべき要件をベースにしてテストケースから考えていく開発手法です。

なので、個人的にはこの「 テストケースを作る 」という段階が重要になってくると考えています。

そして、テストケースが作り終わったら「 3つのサイクルを回して 」開発していきます。

- Red(失敗させて)

- Green(エラーが出ないようにして)

- リファクタリング(正しい形に直していく)

このサイクルを回していくと要件を満たしたことが担保された動くコードが出来上がっていきます。


< golang x TDD >

基本的なやり方は以前書いたエアペアプロにある通りになります。

https://qiita.com/i-dach/items/20b3460f736fb93c53c4#%E3%82%A8%E3%82%A2%E3%83%9A%E3%82%A2%E3%83%97%E3%83%AD%E3%81%AE%E3%82%84%E3%82%8A%E3%81%8B%E3%81%9F

TDDのサイクル通りに

- 「テストケース」を作り、

- 「golangで空のテストを実行してエラーにさせて」

- 「3つのサイクルをぐるぐると回していく」

をひたすら行うだけです。


【まとめ】

golangでTDDをやるとしても特別なことは特にありません。

golangでのテストの書き方とTDDのススメ方さえ把握してれば怖くないので、是非トライしてみましょう!