Slide 1

Slide 1 text

「僕ら」のテストに対する向き合い方 golang.tokyo #37 2024.11.20

Slide 2

Slide 2 text

自己紹介 Sugar Sato (@satoIsSugar) ● 2023年 BuySell Technologies入社 ● 基盤チーム所属(Portal/Account/Approval) PjM ○ アソシエイトマネージャー ● Go / Angular / Serverless ○ Go歴: Go 年目くらい ● 熱帯植物 ○ ビカクシダ ● 猫 ○ Lambda (♀ 2才)

Slide 3

Slide 3 text

プロダクト群「バイセルリユースプラットフォーム Cosmos」の開発が進行中 リユースに必要なすべての機能を提供する 「リユースプラットフォーム Cosmos」の開発が進行中です。 Cosmosを活用して、バイセルグループ全体での業務効率改善やデータドリブン経営の深化を目指しています。 リユースプラットフォーム Cosmos 自社開発のリユース特化業務基幹システムでありサービス群の集合体 買取申込 買取・査定 在庫管理 販売 多様なチャネルで収益最大化 CRM -顧客対応- 買取種別に応じた最適なシステム構築 Visit -訪問買取 - Store -店舗買取 - Promas -商材マスタ - Appraisal -専門査定 - Stock -在庫管理 - EXS -販売管理 - Core -会員管理- Portal -データ利用- Pocket -データ基盤- 買取 専門チームによる真贋・査定と連携 査定 申込 効率的な顧客対応 在庫 在庫管理の最適・効率化 販売 データ 各事業プロセスにある データを一元管理 :基幹システム

Slide 4

Slide 4 text

本題に入りまして、、、 「みんなテストは好きか〜?」

Slide 5

Slide 5 text

好きだ〜🙌 好きじゃないぞ〜! 正直どっちでもない ど ち らか とい え ば 好 きか も テストこそ正 義 ! 逃げられない戦いがそこにある できることなら逃げたい カバ レ ッジ ! カバレッジ! mock!! testable!! カ バ レ ッジ ! カバレッジ! そ の 術 は オ レに 効 く テ ス タ ブ ル モック! モック! 0!! C1!!

Slide 6

Slide 6 text

ということで、今日は テストにどう向き合っているか話します

Slide 7

Slide 7 text

● 「僕ら」 = 「自分のチーム」 ○ 限定的な話 ■ プロダクトによって向き不向きがある ○ 取り組み話が多め ● WebAPI の Go にまつわるテスト話 ○ OnionArchitecture の情報少し ⚠⚠⚠ 注意 ⚠⚠⚠

Slide 8

Slide 8 text

アジェンダ テストの基本方針 01 まとめ 02

Slide 9

Slide 9 text

テストの基本方針

Slide 10

Slide 10 text

● ざっくり4つを実施 ○ カバレッジ目標を明確に定めない ○ mock は「なるべく」使わない ○ TDT + AAA パターン ○ テストにも linter を! テストの基本方針

Slide 11

Slide 11 text

カバレッジ目標を明確に定めない

Slide 12

Slide 12 text

メリット ● 盲信的に数値を追うことだけをしなくて済む ○ 「薄い」テストをなくせる ■ OnionArchitecture の入出力だけするコード ■ mock しか通さないテスト ○ 数値以外の明確な理由があるなら納得 ● 優先度の高い機能開発 ○ 適切なリソース配置

Slide 13

Slide 13 text

● ライブラリ等のアップグレードを気軽にできなくなる ○ テストで動作保証 ❌ ○ 障害につながる可能性 ⤴ ● チーム間のテストに対する認識のズレ ○ 「十分なテストとは」 ○ 「特定のファイルだけテストがないのは何故」 ● コード変更時のリスク デメリット

Slide 14

Slide 14 text

カバレッジ測定方法 ● 手順 ○ go test ■ coverprofile 生成 ○ go tool cover ■ html 生成

Slide 15

Slide 15 text

出力されたカバレッジファイル

Slide 16

Slide 16 text

カバレッジ目標を明確に定める場合 ● 70 ~ 80%くらいが良さそう かも ○ カバレッジの目標値は何%にするべきなのか? ■ 注) 元記事内の参照元リンク切れ ■ 「テスト完了条件ではない」 ○ Code Coverage Best Practices ■ 60%: acceptable ■ 75%: commendable ■ 90%: exemplary

Slide 17

Slide 17 text

カバレッジの可視化 ● 予算あり: codecov, coveralls ○ GitHub Actions ○ goveralls ● 予算なし: k1LoW/octocov ○ GitHub Actions ○ 公開 ■ GitHub Pages にホスト ■ 認証あり静的ホスト (S3 / GCS)

Slide 18

Slide 18 text

k1LoW/octocov ● tbls などでも有名な k1LoW さん ● 個人的に愛用🙏 ● 手順 ○ .octocov.yml 作成 ○ GitHub Actions ■ go test ■ go tool cover ■ k1Low/octocov-action

Slide 19

Slide 19 text

mock は「なるべく」使わない

Slide 20

Slide 20 text

mock を使うメリット ● カバレッジの担保しやすさ ● テスト実行時間が短くなる ● 依存するリソースを用意しなくていい ● 簡単な動作確認ができる ○ レイヤ毎の入出力 ■ usecase ←→ repository

Slide 21

Slide 21 text

● 想定するシナリオをテストしづらい ● 依存サービスのバージョン互換性を保たない ● ライブラリの習熟 ○ gomock ○ mockery ○ moq mock を使うデメリット

Slide 22

Slide 22 text

● usecase テストがメイン ○ データ永続化(repository)で複雑 なクエリがある ■ mock を使用するならレイヤ毎 にテストをする ● 実装コストに見合わない ○ どうしても必要なら testify で mock を追加する その上で mock を使わない理由

Slide 23

Slide 23 text

mock を使う線引き ● 「なるべく」使わないスタンスは変えない ○ その上で ■ 依存サービスの挙動が重要でない ■ エッジケースの再現をしたい ■ 外部 API のリクエストがある ● dockertest や testcontainer でリソース準備が大変 ● httptest をつかう ■ etc…

Slide 24

Slide 24 text

TDT + AAA パターン

Slide 25

Slide 25 text

● Table Driven Testing ○ データとロジックを分離 ○ 冗長性の排除 ○ 新しいテストケースの追加 ○ 入出力の期待値の理解 TDT

Slide 26

Slide 26 text

TDT ● Table Driven Testing ○ 分岐が発生してしまう ケースがある ■ 正常・異常の返り値で エラーをアサーションする

Slide 27

Slide 27 text

AAA パターン ● Arrange Act Assert ○ TDT の課題をクリアさせる ○ 今年の GoConf でも同じ考えを...! ■ Table-driven testing に縛られないGoのテストパターン

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

テストにも linter を!

Slide 30

Slide 30 text

テストにも linter を! ● 以前の発表 (golang.tokyo #35)

Slide 31

Slide 31 text

golangci-lint の適用 ● チームで運用する golangci-lint の向き合い方 ○ 「テストコードもプロダクションコード同様に扱い品質を保ちたい」 ○ 「どうしても ignore ルールを追加したい時はチームで相談する」

Slide 32

Slide 32 text

以上が 「僕ら」の実施していることです 🙌

Slide 33

Slide 33 text

まとめ

Slide 34

Slide 34 text

まとめ ● カバレッジに明確な目的をもたす ● テストを簡潔にすることをめざす ● 方針を都度変えていくことも大事 ○ 全部は話せていない ■ fixture ■ e2e ■ testify を使う理由 ■ 失敗例

Slide 35

Slide 35 text

テストに秩序を!

Slide 36

Slide 36 text

Thank you

Slide 37

Slide 37 text

引用 ● https://sgash708.github.io/hbd-go/cover.html#file0 ● https://qiita.com/odekekepeanuts/items/d02eb38e790b93f44728#%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82 %B8%E3%81%AE%E7%9B%AE%E6%A8%99%E5%80%A4%E3%81%AF%E4%BD%95%E3%81%AB%E3%81%99%E3%82%8B %E3%81%B9%E3%81%8D%E3%81%AA%E3%81%AE%E3%81%8B ● https://testing.googleblog.com/2020/08/code-coverage-best-practices.html ● https://speakerdeck.com/sgash708/timudeyun-yong-suru-golangci-lint-noxiang-kihe-ifang?slide=45 ● https://about.codecov.io/blog/getting-started-with-code-coverage-for-golang/ ● https://docs.coveralls.io/go ● https://github.com/mattn/goveralls ● https://github.com/k1LoW/octocov ● https://speakerdeck.com/abekoh/table-driven-testing-nifu-rarenai-gonotesutopatan?slide=12