Upgrade to Pro — share decks privately, control downloads, hide ads and more …

testingパッケージを使った Webアプリケーションテスト 単体テストからE2Eテストまで / gocon2022spring

testingパッケージを使った Webアプリケーションテスト 単体テストからE2Eテストまで / gocon2022spring

https://gocon.jp/2022spring/sessions/a10-s/

Go Conference 2022 Springの登壇資料です。
資料の中のリンクはブログで紹介しています。

https://budougumi0617.github.io/2022/04/25/gocon2022spring/

Eb6be531bcfaa99714d8d3b48665a5a9?s=128

Yoichiro Shimizu

April 25, 2022
Tweet

More Decks by Yoichiro Shimizu

Other Decks in Technology

Transcript

  1. © 2012-2022 BASE, Inc. 1 #goconA @budougumi0617 testingパッケージを使った Webアプリケーションテスト 単体テストからE2Eテストまで

    Go Conference 2022 Spring BASE株式会社 清水 陽一郎(@budougumi0617)
  2. © 2012-2022 BASE, Inc. 2 #goconA @budougumi0617 自己紹介 所属 BASE

    株式会社 BASE BANKチーム Tech Lead Go、New Relicや自動化など。 趣味 ブログ: https://budougumi0617.github.io/ SNS Twitter : @budougumi0617  Github : https://github.com/budougumi0617 2022/07/20 商業誌出版予定 清水 陽一郎 (しみず よういちろう)
  3. © 2012-2022 BASE, Inc. 3 1 2 3 #goconA @budougumi0617

    WHY - なぜテストするのか? WHAT - 何をテストするのか? HOW - どうテストするのか? 今日の話
  4. © 2012-2022 BASE, Inc. 4 1 2 3 #goconA @budougumi0617

    テストを書くことで自信をもって変化を積み上げる テストと設計は表裏一体 なぜテストするのか意識する 今日伝えたいこと
  5. © 2012-2022 BASE, Inc. 5 #goconA @budougumi0617 • 「テストがないコードはレガシーコード」だから? •

    プロジェクトにカバレッジの基準があるから? Why Test
  6. © 2012-2022 BASE, Inc. 6 #goconA @budougumi0617 • テストを書いたほうがいいことはみんな知っている •

    “golang やりたいテスト形式”でググればHOWはだいたい出てくる • 「なぜ」このやり方のテストを選択しているのか?が参考になれば🙏 「なぜ」が一番大事
  7. © 2012-2022 BASE, Inc. 7 #goconA @budougumi0617 • テストピラミッド •

    アジャイルテストの4象限 • 様々なテストを黄金比通りに作ればいいのか? • 「あったほうがいい」からやるのか? • プロダクトの品質にどう寄与しているのか テストを書く https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html https://www.informit.com/articles/article.aspx?p=2253544&ranMID=24808
  8. © 2012-2022 BASE, Inc. 8 #goconA @budougumi0617 • バグを補足できる •

    変化を可能とする ◦ テストがあれば、検証しながらコードの動きを素早く変更できる ◦ テストがなければ、コードが良くなっているのか悪くなっているのかが本 当にはわ からない。 • レビューやデバッグの効率化 • 結合度を低下させ、柔軟性をもたせる • 実装前にAPIを観察できる Why Test
  9. © 2012-2022 BASE, Inc. 9 #goconA @budougumi0617 • ネットショップ 作

    成 サービスBASE オーナー様向けサービス • BASEの 売 上 をそのまま Visa提携店で使える • GoはAPIサーバ お題: BASEカード
  10. © 2012-2022 BASE, Inc. 10 #goconA @budougumi0617 • リポジトリ ◦

    永続化処理、外部APIを実行するためレイヤー • ユースケース ◦ 永続化処理やドメインロジックを組み合わせてユースケースを表現するレイヤー • HTTPハンドラー ◦ JSONパース/レンダリングするレイヤー ざっくり3層アーキテクチャ
  11. © 2012-2022 BASE, Inc. 11 © 2012-2022 BASE, Inc. 11

    リポジトリ関連のテスト
  12. © 2012-2022 BASE, Inc. 12 #goconA @budougumi0617 • DB処理用のメソッド •

    UseCaseからコネクションをもらう実装 ◦ トランザクション制御をユースケース上でするため リポジトリ関連のテスト
  13. © 2012-2022 BASE, Inc. 13 #goconA @budougumi0617 • 実DBを使ってテストしている ◦

    sqlxを使ってCASE式などを使ったSQLを書いているから ◦ gormやentなら不要かもしれない • sql-mock ◦ 期待通りのSQLが発行されただけ ◦ 実際にデータが取れるかはわからない • fixtureはシンプルなカタチで用意 リポジトリ関連のテスト
  14. © 2012-2022 BASE, Inc. 14 #goconA @budougumi0617 • CI上で実行する時などは環境変数をみる ◦

    CircleCIだったらCIRCLECIが定義されている • Cleanupでレコードを消す リポジトリ関連のテスト
  15. © 2012-2022 BASE, Inc. 15 © 2012-2022 BASE, Inc. 15

    ユースケースのテスト
  16. © 2012-2022 BASE, Inc. 16 #goconA @budougumi0617 • ユースケースレイヤーでトランザクション制御 ◦

    抽象化による難読化を避けるため ◦ 参考: https://speakerdeck.com/sonatard/ideal-and-reality-of-abstraction-by-repository ユースケース関連のテスト
  17. © 2012-2022 BASE, Inc. 17 #goconA @budougumi0617 • 入力に対する期待シナリオでリポジトリ層やロジックが呼ばれているか ◦

    実DBは使っていない ◦ sql.DBオブジェクトやTxをモックしている ▪ Commit()が実行されたか ◦ 永続化データが正しくロールバックされるかはDBの実装による ▪ この層ではトランザクションをリポジトリに渡したか、Commit()を呼んだのかRollback()を呼 んだのか分かればよい ユースケース関連のテスト
  18. © 2012-2022 BASE, Inc. 18 © 2012-2022 BASE, Inc. 18

    HTTPハンドラーのテスト
  19. © 2012-2022 BASE, Inc. 19 #goconA @budougumi0617 • JSONパースとJSONレンダリングくらいの実装 HTTPハンドラーのテスト

  20. © 2012-2022 BASE, Inc. 20 #goconA @budougumi0617 • httptest pkgを使った素朴なテスト

    • 入力/期待JSONをファイルにしている ◦ API仕様を理解しやすい ▪ testdata • card_setting ◦ request ▪ normal_case.json ◦ response ▪ ok.json ▪ invalid_setting.json • issue_card • … HTTPハンドラーのテスト
  21. © 2012-2022 BASE, Inc. 21 © 2012-2022 BASE, Inc. 21

    APIクライアントのテスト
  22. © 2012-2022 BASE, Inc. 22 #goconA @budougumi0617 • モックサーバを自作してhttptest.Serverで起動している •

    http.ClientのTransport(RoundTripper)をすげ替える選択肢もある • 再利用性の観点で自作している ◦ 外部連携先に接続できない開発環境でダミーサーバとして利用するため APIクライアントのテスト
  23. © 2012-2022 BASE, Inc. 23 © 2012-2022 BASE, Inc. 23

    E2Eテスト
  24. © 2012-2022 BASE, Inc. 24 #goconA @budougumi0617 • カード決済の難しさ(ひとつの決済に複数の通信が行われる) ◦

    オーソリ(残高確定) ◦ 確定 ◦ 強制確定 ▪ 為替変動による決済金額変動 ◦ 強制確定(マイナス) ▪ 確定後にキャンセル ▪ 一部だけキャンセル(年間払いを途中でキャンセルetc) シミュレーションテスト(E2Eテスト)
  25. © 2012-2022 BASE, Inc. 25 #goconA @budougumi0617 • デグレなしでエッジケース対応したい •

    決済レコードに状態を持たせたテストがしたい ◦ オーソリ、確定、強制確定(マイナス)を処理した決済レコードのステータス • 複数回リクエストを処理した結果なのでユニットテストでは検証できない • 事前データを作る形式では”都合の良い”データになっている可能性 シミュレーションテスト(E2Eテスト)
  26. © 2012-2022 BASE, Inc. 26 #goconA @budougumi0617 • メルカリの柴田さんが書いていたE2Eフレームワークの簡易版 ◦

    https://engineering.mercari.com/blog/entry/gears-microservices/ • 実DBに接続した本番同等のルーティングをhttptest.Serverで起動 • 決済業者を模して残高確認webhookを複数回実行 • DB上のレコードを検証 シミュレーションテスト(E2Eテスト)
  27. © 2012-2022 BASE, Inc. 27 #goconA @budougumi0617 • テストケースの実装など、メンテナビリティは低い •

    問題ない ◦ ( 新 たなエッジケースの)テストケースが 追 加 されることはあっても、 既存のテストケースが変わることはない ◦ 仕様が変わる時 == クレジットカードの決済の仕組みが変わるとき ◦ 完全なブラックボックステストなので脆くない • テストがあることで決済ロジックも安心して変更できる シミュレーションテスト(E2Eテスト)
  28. © 2012-2022 BASE, Inc. 28 1 2 3 #goconA @budougumi0617

    テストを書くことで自信をもって変化を積み上げる テストと設計は表裏一体 なぜテストするのか意識する まとめ
  29. © 2012-2022 BASE, Inc. 29 © 2012-2022 BASE, Inc. 29

    Tips
  30. © 2012-2022 BASE, Inc. 30 #goconA @budougumi0617 • go test

    shuffle=on ./… ◦ 順不同に実行される ◦ non-parallelなテーブルサブテストは逐次のまま ▪ mapにするとよい • go test -count=1 ./… ◦ キャッシュを無視できる ◦ 競合状態の再現のときなど ◦ 明示的にキャシュを消すならば go clean -testcache Tips: よく使うgo testオプション
  31. © 2012-2022 BASE, Inc. 31 #goconA @budougumi0617 • go test

    -race ./… ◦ 競合状態を発見してくれる ◦ テスト実行中に"実際に起きない"と検知できない ◦ CI上の実行ではひとまずつけておいてよい Tips: よく使うgo testオプション
  32. © 2012-2022 BASE, Inc. 32 #goconA @budougumi0617 • t.Helper() •

    t.Cleanupが増えてすっきり書ける • 共通化 ◦ JSONファイル比較アサーション ◦ 事前データの流し込み関数 Tips: ヘルパー
  33. © 2012-2022 BASE, Inc. 33 #goconA @budougumi0617 • export_testを参照できるのはそのパッケージか..._testパッケージだけ ◦

    Go Fridayこぼれ話:非公開(unexported)な機能を使ったテスト ▪ https://engineering.mercari.com/blog/entry/2018-08-08-080000/ • go test ./… ◦ パッケージごとに別プロセスで動く(パッケージ間でメモリ空間が独立) ◦ 並行テストの動き方 ▪ Go言語でのテストの並列化 〜t.Parallel()メソッドを理解する〜 • https://engineering.mercari.com/blog/entry/how_to_use_t_parallel/ • testdataディレクトリ ◦ The go tool will ignore a directory named "testdata", making it available to hold ancillary data needed by the tests. Tips:
  34. © 2012-2022 BASE, Inc. 34 #goconA @budougumi0617 • github.com/golang/mock ◦

    Goにおけるモックのデファクトツール ◦ モックメソッドの引数に指定した構造体の差分が見にくい時 ▪ github.com/budougumi0617/cmpmock • github.com/DATA-DOG/go-sqlmock ◦ DBをモックしてくれる ◦ いい感じに初期化されたsql.Txがほしいときなどに使う。 ▪ sql.Txは適切に初期化されていないとCommitなど実行したときに失敗する Tips: OSS
  35. © 2012-2022 BASE, Inc. 35 #goconA @budougumi0617 • github.com/google/go-cmp ◦

    構造体の比較をよしなにしたいとき ◦ cmpoptsサブパッケージはちゃんと見ておいたほうがよい ◦ SortMaps, IgnoreFields, IgnoreTypes etc… • github.com/k1LoW/octocov ◦ しゅっとカバレッジ可視化できる Tips: OSS
  36. © 2012-2022 BASE, Inc. 36 #goconA @budougumi0617 • github.com/stretchr/testify ◦

    https://pkg.go.dev/github.com/stretchr/testify/assert#Eventually • github.com/onsi/gomega ◦ https://pkg.go.dev/github.com/onsi/gomega#Eventually ◦ イベント駆 動な結 果 整 合 性までテストしたい場 合は素 直にtestifyやgomegaをつ かったほうがよさそう Tips: OSS