golang.tokyo #17に参加してきました!
golang.tokyo って?
プログラミング言語Goの導入企業メンバーが集まり、Goの普及を推進するコミュニティです。 トークイベント、ハンズオン、etcのイベントを開催していく予定です。
golang.tokyo #17 は、
テーマが「今あらためてテストの話」で、テストについての回でした!
会場は freee さん。
美味しい食事やお酒をたくさんご用意いただきました...!
各発表のポイントや気になった点について、まとめていきたいと思います。
タイムテーブル
時間 | 内容 |
---|---|
19:00 ~ | 開場・受付 |
19:30 ~ 19:40 | オープニング |
19:40 ~ 20:10 | Tour of testing by budougumi0617 |
20:10 ~ 20:40 | 非公開な機能を使ったテスト by tenntenn |
20:40 ~ 21:10 | 休憩 |
21:10 ~ 21:20 | LT1 外部環境への依存をテストする by duck8823 |
21:20 ~ 21:30 | LT2 Developer-friendly なテストを考える by izumin5210 |
21:30 ~ 21:40 | LT3 止めたいのに止められないテストの話 by knsh14 |
21:40 ~ 21:50 | 終了・撤収 |
Tour of testing by budougumi0617
1つ目は、@budougumi0617 さんによる Tour of testing in 2018 の発表でした。
説明された内容や、文中のリンクは以下のブログに記載されています。 https://budougumi0617.github.io/2018/08/19/go-testing2018/
自己紹介
Today's contents
Today's goal
Introduction 01
- テストの書き方どう覚える?
- 毎リリースそれなりに変更・追加がある
Start test 02
- Basic and Naming
- ファイル名はxxx_test.go
- go test のときだけビルド
Test data を用意する
- testdataディレクトリに置く
- pkgとして認識されない
- testdataディレクトリに置く
Execute test
# カレントパッケージのテストを実行する $ go test # パスで指定されたパッケージのテストを実行する(相対パス指定が可能) $ go test ./table # サブパッケージを含めたパスで指定されたパッケージ以下のテストを全て実行する $ go test ./... # 特定のテストコードだけを実行する(テスト対象も含めて実行する) $ go test sum_test.go sum.go # カレントパッケージ配下にある"Minus"というサブテスト(後述)だけを実行するとき $ go test ./... -v -run /Minus # Race condition の検出 $ go test ./... -race
- go vet を抑制する
- $ go test -vet=off
- Go 1.10からテストの実行前にgo vet が実行される
Test Cache
- Go 1.10から go build/testの結果がキャッシュされる
- キャッシュを削除する / go clean -testcache
- キャッシュなしで実行 / go test -count=1
-parallel nオプションで最大並行実行数を制御する
- T.Parallel()メソッドが呼ぶテストケースは並行実行
- $GOMAXPROCS
- parallel nオプションのnで同時実行数を制御
cpu listで$GOMAXPROCSを変更しながらテストする
- playgroundでテストを実行できる
- 実はそのまま動かせるようになったのは最近
How to write test
- テストコードのパッケージ
- 同ディレクトリに複数パッケージは通常許されない
- 例外的に"xxx"と"xxx_test"は共存可能
- TB.Error / TB.Errorf
- テストの失敗が記録される
- 後続処理は継続される
- TB.Fatal / TB.Fatalf
- 失敗が記録され、テストケースが即時終了する
- その場で宣言済み
- TB.Fail
- TB.Error / TB.Errorf が内部的に呼んでいる
- TB.FailNow
- TB.Fatal / TB.Fatalf が内部的に呼んでいる
- TB.SkipNow / TB.Skip
- テストケースを無効化する
- TB.Log / TB.Skip
- -vオプション、あるいはFailしたときにログ出力
- ベンチマーク時は常に出力
- want / got
- expected? NO!
- actual? NO!
- 変数名は短いほうがGo way
Get coverage
- Goは標準機能でテストカバレッジを計測できる
- Go1.10からは複数パッケージのカバレッジも簡単に取得できるようになった
- go test -cover ./...
- go toolでカバレッジの計測結果をHTMLに出力できる
Today's summary
- go testコマンド / testing.T を改めて確認
- Go 1.10までの仕様を復習
- ベタープラクティスをまとめる
- ひとつでも多く新しい発見をしてもらう
質疑応答
Q . 並行テストの使い方は?
- 「あまり意識してないですが、単純に遅いので早くするため。 個人的にはやってないが、プロジェクトではやっています。」
Q . 並行のオーバーヘッドは?何行からやる?
- 「意識して遅くなることはないと感じています。」
@budougumi0617 さんのスライドは、こちらも大変参考になりました!
※ クイズ形式みたいになっていて、解きながら読み進められます
初級者向けGoの落とし穴と解説 / Traps and Explanations in Go
非公開な機能を使ったテスト
2つ目は、@tenntenn さんによる 非公開な機能を使ったテスト の発表でした。
内容的には「こちらに、ちょっと情報を足したバージョンです」とのこと。
Go Fridayこぼれ話:非公開(unexported)な機能を使ったテスト #golang
TL;TD(too long; didn't read.)
- テストはテスト対象と別のパッケージにしよう
- 別パッケージだと非公開な機能にアクセスできない
- export_test.go というファイルを使うと解決する
テストはテスト対象と別のパッケージにしよう
- テストが外部のパッケージになる
- テスト対象のパッケージのユーザーと同じ視点で書く必要がある
- Exampleテストを使う手もある
- 使いづらい部分を早期に発見できる
- テストが内部のコードに依存しなくなる
- 公開(exportedな)された機能にしかアクセスできない
- 非公開な機能にはアクセスできない
別パッケージだと非公開な機能にアクセスできない
- 内部で使用している複雑な機能をテストしたい
- unexportedな関数で実装されている
- いろんなところで呼ばれている
- 関数単体でテストしたい
- 本当に非公開にする必要があるのか?
- そんな複雑な処理をunexportedにしておく必要があるのか?
- internalパッケージにする?
- internalパッケージのexportedな機能とする = テストできる
- 別のパッケージに切り出す?
export_test.go というファイルを使うと解決する
// export_test.go package mypkg // テスト対象と同じパッケージ const ExportMaxValue = maxValue
// テストコード func TestMypkg(t *testing.T) { if doSomething() > mypkg.ExportMaxValue { // ExportMaxValue が公開されているのでアクセスできる t.Error("Error") } }
- テストのときだけビルド対象にする
- *_test.goはgo testのときだけビルドされる
- _test.goをつけてテスト対象と同じパッケージにする
- テストのときにしかビルドされないファイルになる
- テスト対象パッケージのテスト用の機能になる
まとめ
別のパッケージにすることで、
ユーザーの気持ちになってテストが書けるというのは面白いと思いました...!
@tenntenn さんには Gopher 道場でもお世話になっていますが、
スライドを流しながら、スライド外の細かい解説までして下さるので、
聞いていて本当に興味深いです...!
参考
メルペイがGopher道場をサポートする理由 #メルペイなう vol.16 #gopherdojo - mercan(メルカン)
最後に
LTいただいた方々の資料も、こちらにまとめておきます!
Tips for develoepr-friendly testing #golangtokyo - Speaker Deck