Slide 1

Slide 1 text

Kanon (@ysknsid25) #yapcjapan テストコードの品質を 客観的な数値で担保しよう 〜 Mutation Testのすすめ 〜

Slide 2

Slide 2 text

README @ysknsid25 水瀬いのりさん が推し 表紙のアイコンは公式配布のものです。 https://x.com/tonikakuhayate/status/1806583319951233034?s=46&t=zwt7nxAvhST7_30NZnyMTQ

Slide 3

Slide 3 text

この発表のゴール 3 ● Mutation Testについて知っていただく ● 「Mutation Testを試しにやってみようかな」と思ってい ただく

Slide 4

Slide 4 text

4 Mutation Testとは?

Slide 5

Slide 5 text

コードに意図的なバグを植え付けることで、 テストコードの検証が適切に行われているか? を測定する手法 5 Mutation Testとは?

Slide 6

Slide 6 text

6 自分が自動テストに対してずっと思ってたこと Mutation Testとは? テストコードがほんまに正しく書けてるか分からんのに、 テストコードを書いて「カバレッジx%やからヨシ!」 でほんまに品質って担保できてるんか?

Slide 7

Slide 7 text

7 カバレッジレポートの罠 Mutation Testとは? ● 通常のカバレッジメトリクスは嘘をつく ● 例えば以下の(極端なテストケース)など コードサンプル javascript-testing-best-practice

Slide 8

Slide 8 text

8 そこで登場するのが Mutation Test Mutation Testとは? ● Mutation = (突然) 変異 ○ コードを意図的に変更し、バグを植え付ける ○ ex) a===0 を a !== 0 と変異させる ○ その後テストを実行し、正しいテストが書かれていなければアサーションが エラーとなるはず ○ エラーとならなかった箇所がきちんと検証されていないと判断できる ● Googleでは2017~18年ごろから全社的に導入されているっぽい 参考:Googleにおける突然変異テストの状況 変異の内容と種類

Slide 9

Slide 9 text

9 Mutation Test に関わる指標 Mutation Testとは? ● Killed ○ 変異後、成功すべきテストが失敗したことにより検知された変異の数 ● Survived ○ 変異後、失敗すべきテストが成功したことにより検知された変異の数 つまり、Survivedの数が多ければ多いほどテストコードの品質が低い

Slide 10

Slide 10 text

10 Mutation Test に関わる指標 Mutation Testとは? Mutation Score = Killed / Total * 100 この割合が高いほど品質がよい

Slide 11

Slide 11 text

11 百聞は一見に如かず

Slide 12

Slide 12 text

12 Stryker を使っていろいろと見てみます 解像度を上げていく ● Mutation ライブラリ ● 変異を自動で作ったり、レポート作ったり ● 対応言語 ○ JS ○ C# ○ Scala Playground (C#) があるのでそれを使ってみる

Slide 13

Slide 13 text

13 Mutation Reportを見てみる 解像度を上げていく

Slide 14

Slide 14 text

14 “失敗すべきテストが成功するとは?” 解像度を上げていく これを覚えておい てください これを覚えておい てください

Slide 15

Slide 15 text

15 “失敗すべきテストが成功するとは?” 解像度を上げていく

Slide 16

Slide 16 text

16 “失敗すべきテストが成功するとは?” 解像度を上げていく 変異前も前後も 結果は100 =変異してるのに テストは成功する この場合は 引数が適切でない

Slide 17

Slide 17 text

17 適切なテストにするには? 解像度を上げていく テストパラメータを 修正し、再実行

Slide 18

Slide 18 text

18 LGTM👍 解像度を上げていく スコアアップ 🎉 Survivedだった 変異が消えた

Slide 19

Slide 19 text

19 実際に導入して困ったこと

Slide 20

Slide 20 text

20 今回の導入環境など ● Nest.js (v10.4.1) ○ TypeScript (v5.5.4) ○ node (v20.11.0) ○ Vitest (v2.0.5) ○ Stryker (v8.5.0) ● マシンはMBA M2 16GB ● 新規プロジェクトに導入

Slide 21

Slide 21 text

21 余談: TypeScript でも Strykerは変異を起こしてくれる レポートを見た感じ TSに対して変異を作っている 設定は特にしてない

Slide 22

Slide 22 text

22 実戦で困ったこと ● 正攻法で実行すると死ぬほど遅い ● Stryker Dashboardがプライベートリポジトリだと使えない

Slide 23

Slide 23 text

23 正攻法で実行すると死ぬほど遅い 実戦で困ったこと CIに入れられるわけない Unit テストは 2,30秒くらいで終わっ てる

Slide 24

Slide 24 text

24 なぜ遅いのか? ● 変異の数はこの式で決まる ○ 変異発生対象ファイル × 変異の種類 ● 全体の実行時間はこの式で決まる ○ 変異の数 × Unitテストケースの実行時間 ● Strykerのデフォルト設定 ○ 全てのファイル × 全変異パターン ● よって変異発生対象ファイルと変異の種類を絞って あげればいい 正攻法で実行すると死ぬほど遅い 変異発生対象ファイルを指定 除外する変異発生対象を指定

Slide 25

Slide 25 text

25 そう簡単に改善サセネーヨ ★ 正攻法で実行すると死ぬほど遅い CIに (ry

Slide 26

Slide 26 text

26 実行時間で困った時の解法: 差分実行を使う ● incremental オプション ○ incremental: true で設定 ○ jsonで前回の結果を保存 ○ 変異対象のファイルに差分があった箇所のみ新たに(再度)変異を発生させ て実行 正攻法で実行すると死ぬほど遅い

Slide 27

Slide 27 text

27 LGTM👍 正攻法で実行すると死ぬほど遅い ただ、変更箇所が多いと 実行時間は比例する が、PRを小さくするという意識を チームに植え付けられたので 結果オーライ

Slide 28

Slide 28 text

28 Stryker Dashboardがプライベートリポジトリに使えない 実戦で困ったこと ● やろうとしていたこと ○ GHAでMutation Testを定期実行して、レポートを取得 ■ Mutation Scoreがキープできているか? ■ Mutation Scoreをより高くしていくために、どこを直す必要があるか? ● なぜ? ○ チームメンバーの品質への意識の向上 ○ 修正を未経験新入社員にやってもらうことでプロダクションに影響のないところでコー ディング経験を積んでもらえる

Slide 29

Slide 29 text

29 Google Cloud Storageへ送信 + Slack通知 ● Workload Identity連携でGCSへ送信 ● バケットのURLをSlack通知 ● バケットは非公開&権限付与されたアカウントのみ 閲覧可能な設定 ● GCSに置いたレポートはライフサイクル管理を設定 することで、一定期間が過ぎたものは削除される Stryker Dashboardがプライベートリポジトリで使えない

Slide 30

Slide 30 text

30 LGTM👍 Stryker Dashboardがプライベートリポジトリで使えない 推しに通知してもらえて wktk

Slide 31

Slide 31 text

31 導入した結果、どうなったか?

Slide 32

Slide 32 text

32 Unitテストのカバレッジ ● 一般的には65% ~ 80%くらいを目指すのが良いくらいとされるなか、かなり高い数値を キープできている (2024/09/29現在) ● Mutation Testがあるおかげで、ある程度この数値も信頼できるようになった ● 特に無理してテストを書いている感じはない ● そもそも全体のStatementsは1805程度なので比較的小さい 導入した結果、どうなったか?

Slide 33

Slide 33 text

33 Mutation テストのカバレッジ ● こっちは77%くらいなのでまずまず ● Strykerにも閾値を設定できて(thresholdオプション)、今は50%以上なら CIはコケないようにしている 導入した結果、どうなったか?

Slide 34

Slide 34 text

34 その他感想 ● 品質への意識が高まっただけでなく、結果的にPRを小さくする文化が浸透し たのはよかった ● 今回は小さめのプロジェクトに導入したおかげでわりかし早く実行できている が、大規模なプロジェクトに後から入れるのはしんどそう ○ 入れる場合、変異対象や種類を部分的に入れて、徐々に拡張していくの がよさそう ● CIのタイミングでは「どこがSuvivedしているか?」を知ることができない 導入した結果、どうなったか?

Slide 35

Slide 35 text

35 PHPのMutationライブラリ・Infection にはそれがある CIのタイミングでは「どこがSuvivedしているか?」を知ることができない

Slide 36

Slide 36 text

36 自動テスト・品質向上の一助になれば幸いです

Slide 37

Slide 37 text

37 ご清聴、あざざました

Slide 38

Slide 38 text

38 📢 おわりに宣伝 🙏 オフラインLT会を 神戸で開催してます! TS+周辺技術 Figma、npmなどなど 範囲が広いので登壇しやすい!