Go1.24時代の ユニットテスト品質向上
by
shotaro watanabe
×
Copy
Open
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Go1.24時代の ユニットテスト品質向上 Go Conference 2025 Sunday, 28 Sep 2025 2:00 pm - 2:20 pm 株式会社ジーニー 渡邉祥太朗 1
Slide 2
Slide 2 text
自己紹介 株式会社ジーニーでGoを書いている 渡邉 祥太朗(わたなべ しょうたろう)です GitHub: shotarowatanabe6 X: @5wee7 2
Slide 3
Slide 3 text
アジェンダ - ユニットテストが信頼できなかった話 - ユニットテストの改善例 - uber-go/mock - testing.T.Context() - 実装指針・文化醸成 3
Slide 4
Slide 4 text
ユニットテストが信頼できなかった話① - テストが外部APIやDBに依存し、不安定 - その箇所のテストを書くのをやめよう(実話) - 内部実装に依存し、些細な実装変更でテストが落ちる 4
Slide 5
Slide 5 text
ユニットテストが信頼できなかった話② - goroutineリークでCIが不安定 テスト1 OK テスト2 OK テスト4 OK or Fail テスト3 Leak テスト4で エラーが出ている...? テスト1〜3のどこかで リークしている...? 5
Slide 6
Slide 6 text
本日のゴール 信頼できる ユニットテスト 6
Slide 7
Slide 7 text
信頼できるユニットテスト - uber-go/mock - 生成したモックにより速く・安定して実行でき 些細な変更ではテストが落ちない - testing.T.Context() - goroutineリークのミスを軽減 7
Slide 8
Slide 8 text
uber-go/mock 8
Slide 9
Slide 9 text
uber-go/mock mockgen (以下略)コマンド または go generate ./… コマンド モックファイルが生成される 9 mockgen -source=db.go -destination=mock_db.go -package=db
Slide 10
Slide 10 text
uber-go/mock 外部依存を注入 key1にvalue1を返させる 10 mockDB.EXPECT().Get(“key1”) .Return(“value1”)
Slide 11
Slide 11 text
uber-go/mock 11
Slide 12
Slide 12 text
ユニットテストが信頼できなかった話①(再掲) - テストが外部APIやDBに依存し、不安定 - その箇所のテストを書くのをやめよう(実話) - 内部実装に依存し、些細な実装変更でテストが落ちる 12
Slide 13
Slide 13 text
uber-go/mock テストのために実装自体を考える必要がある問題 - DI (Dependency Injection) - 初期の実装コストが高い - コード量が増える - 小規模なアプリケーションでは過剰な場合もある VS 13
Slide 14
Slide 14 text
testing.T.Context() 14
Slide 15
Slide 15 text
testing.T.Context() 15 t.Cleanup() の実行前 または テスト終了時に contextをキャンセルしてくれる 1. contextを含むテストが書きやすく & 読みやすくなった 2. goroutineを扱う複数のテストを実行する場合に デバッグが楽になる
Slide 16
Slide 16 text
ユニットテストが信頼できなかった話②(再掲) - goroutineリークでCIが不安定 テスト1 OK テスト2 OK テスト4 OK or Fail テスト3 Leak テスト4で エラーが出ている...? テスト1〜3のどこかで リークしている...? 16
Slide 17
Slide 17 text
testing.T.Context() // 1. キャンセル可能なコンテキストを作成 ctx, cancel := context.WithCancel(context.Background()) // 2. テスト終了時にcancel()を呼びだす defer cancel() go doSomething(ctx) // 1. t.Context()を呼びだす ctx := t.Context() go doSomething(ctx) 17
Slide 18
Slide 18 text
testing.T.Context() goroutineを使用したworkerに対するテスト例 https://go.dev/play/p/NF2Xm209xZE?v=goprev gomockと組み合わせた例 https://go.dev/play/p/s_B_nPFlN9f?v=goprev https://github.com/shotarowatanabe6/testing_context_example 18
Slide 19
Slide 19 text
t.Context() でcontextを作成 t.Cleanupの前にcontextがキャンセルされる 19
Slide 20
Slide 20 text
GetData(any, “key1”)の際に以下を実 行 “key1” へのアクセスを httptest t.Context() を使用 contextがキャンセルされず正常に終了 20
Slide 21
Slide 21 text
GetData(any, “key1”)の際に以下を実 行 “key1” へのアクセスを httptest t.Context() を使用 contextがキャンセルされるまで待つ 21
Slide 22
Slide 22 text
実践指針・文化醸成 そうはいっても - 誰かが書いたコードにユニットテストを実装するのは大変 - ユニットテスト実装の時間が取れない - そもそもテストのために実装自体を疎結合にしないと 22
Slide 23
Slide 23 text
実践指針・文化醸成 - ユニットテストのTipsを集めてチームに共有 - httptest, miniredis, synctest, … - 自分で書いてコードレビューを依頼する(叩き台があると書きやすい ) - 勉強会で共有 - まずは新規実装にだけ テストを書き、体力を付ける - 既存のコードにテストを書くよりも精神的に楽 (良い事例があれば教えてください!) 23
Slide 24
Slide 24 text
Go1.24時代の ユニットテスト品質向上 Go Conference 2025 Sunday, 28 Sep 2025 2:00 pm - 2:20 pm 株式会社ジーニー 渡邉祥太朗 24