Share
Embed
ユニットテストの現場の問題を原則に立ち返って考える / think deep unit test practical problem
PHPカンファレンス福岡2019 ( #phpconfuk )で発表するユニットテストの現場の問題についての整理を行っていくトークです。
Kazuki Higashiguchi
June 29, 2019
Transcript
138 slides
-
© - BASE, Inc. X ユニットテストの現場の問題を 原則に⽴ち返って考える PHP Conference Fukuoka
#phpconfuk . . - @hgsgtk -
© - BASE, Inc. . 問題を考えるための基礎となるユニットテストの ⽬的 . 現場の問題の整理‧問題に対する戦略の選択肢 .
テスト戦略に対するメリット‧デメリットの評価 このトークが提供すること -
© - BASE, Inc. お品書き:このトークで取り上げる問題 • 意図が汲み取りにくいユニットテストがあります • 不安定なユニットテストがあります •
変更頻度が⾼いユニットテストがあります -
© - BASE, Inc. このトークの流れ . 取り上げる現場の問題 . ユニットテストの⽬的 .
現場の問題の整理と評価 . まとめ . 参考‧引⽤資料 -
© - BASE, Inc. : @hgsgtk ⾃⼰紹介 東⼝ 和暉 (
Higashiguchi Kazuki ) Backend Engineer (Go, PHP, Python etc) BASE BANK, Inc / Dev Division -
© - BASE, Inc. このトークの流れ .取り上げる現場の問題 . ユニットテストの⽬的 . 現場の問題の整理と評価
. まとめ . 参考‧引⽤資料 -
© - BASE, Inc. お品書き:このトークで取り上げる問題 • 意図が汲み取りにくいユニットテストがあります • 不安定なユニットテストがあります •
変更頻度が⾼いユニットテストがあります -
© - BASE, Inc. このトークでの問題整理フォーマット 現場でのユニットテストの問題 問題 障害 戦略 その課題の難しさ‧取り組みを妨げる障害
障害に対してどのような戦略‧戦術を⽤いるか 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する -
© - BASE, Inc. このトークの流れ . 取り上げる現場の問題 .ユニットテストの⽬的 . 現場の問題の整理と評価
. まとめ . 参考‧引⽤資料 -
© - BASE, Inc. 我々を取り巻く様々なテスト • 受け⼊れテスト • 機能テスト •
統合テスト • ユニットテスト • 負荷テスト • コード品質テスト • etc -
© - BASE, Inc. ユニットテストとは • プログラムを構成する⽐較的⼩さな単位(ユニッ ト)が個々の機能を正しく果たしているかどうか を検証する •
実⾏⼿段として、⼿動によるテスト‧⾃動化テス トが存在する • このトークでは、⾃動化テストを取り上げる -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ ユニットテストの両⾯のコスト Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ -
© - BASE, Inc. (CM)BASEとは ネットショップ作成サービス 「BASE」 ショッピングアプリ 「BASE」 価値の交換をよりシンプルにし、
世界中の⼈々が最適な経済活動を⾏えるようにする。 MISSION -
© - BASE, Inc. このトークの流れ . 取り上げる現場の問題 . ユニットテストの⽬的 .現場の問題の整理と評価
. まとめ . 参考‧引⽤資料 -
© - BASE, Inc. お品書き:このトークで取り上げる問題 • 意図が汲み取りにくいユニットテストがあります • 不安定なユニットテストがあります •
変更頻度が⾼いユニットテストがあります -
© - BASE, Inc. お品書き:このトークで取り上げる問題 • 意図が汲み取りにくいユニットテストがあります • 不安定なユニットテストがあります •
変更頻度が⾼いユニットテストがあります -
© - BASE, Inc. 意図が汲み取りにくいユニットテストがあります 意図が汲み取りにくいユニットテストがあります 問題 障害 戦略 意図が不明瞭なテストコード
“Communicate Intent” -
© - BASE, Inc. “Communicate Intent”(意図を伝える) • テストをメンテナンスする開発者が、理解しやす くメンテナンスしやすいテストにすること •
xUTP(※ )の⾃動テストの原則の⼀つ • 理解が難しいコードは、“Obscure Test”と表現 される ※1 ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 5. Principles of Test Automation / ࣗಈςετͷతɾݪଇΛମܥతʹཧͨ͠ॻ੶ -
© - BASE, Inc. “Obscure Test”(曖昧なテスト) • ひと⽬で理解することが難しいテスト • ドキュメントとしての効果が減り、メンテナンス
コストの⾼いテストにつながる Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 15. Code Smells -
© - BASE, Inc. 意図が汲み取りにくいユニットテストがあります 意図が汲み取りにくいユニットテストがあります 問題 障害 戦略 意図が不明瞭なテストコード
“Communicate Intent” 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Communicate Intent”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ •υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • 作成者の「意図」が伝わること で、テスト対象コードのドキュメ ンテーションとしての価値が⾼ま る -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ •طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ •
ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Communicate Intent”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ •υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • テストの可読性が向上すること で、メンテナンス性の良いコード になる。 -
© - BASE, Inc. “Communicate Intent”の判断 Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ
ͷ ࡞ɾҡ࣋ίετ > • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ •υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • ৽نςετ࡞ίετൃੜ •طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ • ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ -
© - BASE, Inc. +α 失敗の原因を明瞭に伝える適切なエラーレポート • テストコード⾃体が “Communicate Intent”で
あることが重要 • 発想の⼀つとして、Goのユニットテストについて のアイデアを抑える • テスト結果だけで「なぜ失敗したのか」がわかる “適切なエラーレポート” -
© - BASE, Inc. +α Go FAQ: Why does Go
not have assertions? Go⾔語では、アサートを提供していません。ア サートが便利である点は疑う余地はありませんが、 我々の経験的には、プログラマはアサートを、適切 なエラーハンドリングとエラーレポートを考慮せず に済ますためのツールとして使っています。 (※ 原⽂私訳) Refs: https://golang.org/doc/faq#assertions -
© - BASE, Inc. +α Proper error reportingの例 (Go) ===
RUN TestInStatusList --- FAIL: TestInStatusList ( . s) sample_test.go: : InStatusList(deleted) = false, want true FAIL 直接的かつ適切な内容をレポートに込める ex. “f(x) = y, want z”という⼀つの形式 Refs ॻ੶ʰϓϩάϥϛϯάݴޠGoʱ / ୈ11ষ ςετ -
© - BASE, Inc. +α 失敗の原因を明瞭に伝える適切なエラーレポート • ⾔語は違えどエラーレポーティングの考え⽅は頭 の⽚隅に意識しておくとよい •
PHPUnit\Framework\Assert::assertXxxはメッ セージを渡すことができる • テスト失敗原因が分かりづらいかも知れないと 思ったときに意識すると、メンテナンスコストの 低い費⽤対効果の良いテストコードになりうる -
© - BASE, Inc. まとめ: 意図が汲み取りにくいユニットテストがあります 意図が汲み取りにくいユニットテストがあります 問題 障害 戦略
意図が不明瞭なテストコード “Communicate Intent” 判断 評価 . ドキュメンテーションコス トの削減 . 既存テスト維持コストの削 減 . 該当なし > -
© - BASE, Inc. (CM) BASE BANK 銀⾏をかんたんにし、全ての⼈が挑戦できる世の中に MISSION https://thebase.in/yellbank
• BASE, Inc の100%⼦会社 • 即座に資⾦調達ができる⾦融サービ ス「YELL BANK(エールバンク)」 を運営 -
© - BASE, Inc. お品書き:このトークで取り上げる問題 • 意図が汲み取りにくいユニットテストがあります • 不安定なユニットテストがあります •
変更頻度が⾼いユニットテストがあります -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 • 実⾏順序で結果が変わるユニットテスト
• 相互依存するデータベースフィクスチャ -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 • 実⾏順序で結果が変わるユニットテスト
• 相互依存するデータベースフィクスチャ -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 戦略 実⾏順序で結果が変わるユニットテスト
“Keep Tests Independent” -
© - BASE, Inc. “Keep Tests Independent”(テストを独⽴させる) • テストが相互依存‧順序依存する場合、”独⽴性” がない状態
• 独⽴していないテストは、 “Erratic Test”(不安 定なテスト)と呼ばれる Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 5. Principles of Test Automation -
© - BASE, Inc. “Erratic Test”(不安定なテスト) • “sometimes they pass
and sometimes they fail” • 不安定な状態を続けると、他の原因での失敗を⾒ 逃してしまうリスクが有る • この問題のトラブルシューティングは難しい Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 15. Code Smells -
© - BASE, Inc. 逸脱の常態化(normalization of deviance) “テストスイートへ信頼を失い、「常にこのように 失敗する」と思うようになります。” “間違っているものに慣れすぎて、それを正常で問
題ないと徐々に受け⼊れ始めることがあるという考 え⽅です。” Refs ॻ੶ʰϚΠΫϩαʔϏεΞʔΩςΫνϟʱ / 7ষ ςετ - 7.6 ৴པͰ͖ͳ͍੬ऑͳςετ -
© - BASE, Inc. 経験上の主な原因:実⾏順序で結果が変わる • テストセットアップ‧実⾏時に⾏ったグローバル な状態変更を後⽚付けできていない • グローバルな状態変更
• グローバル変数の更新 • トランザクション状態 • テスト実⾏時間 • etc -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 戦略 実⾏順序で結果が変わるユニットテスト
“Keep Tests Independent” 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Keep Tests Independent”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ •ܽؕͷૣظൃݟʹΑΔ मਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • “Erratic Test”(不安定なテス ト)回避効果 • 別の⽋陥‧問題を⾒逃してしまう リストの低下 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ •طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ •
ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ •ܽؕͷૣظൃݟʹΑΔ मਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • “Erratic Test”(不安定なテス ト)回避効果 • トラブルシューティングの難しい コストの掛かる現象の回避 “Keep Tests Independent”メリット -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ •طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ •
ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ •Ϣχοτςετͷ ֶशίετൃੜ “Keep Tests Independent”のデメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ •ܽؕͷૣظൃݟʹΑΔ मਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • Super classで共通のtearDown をしていても、個別で必要だった ⽚付けの⾒逃しや⽚付け忘れはあ りうる • その際のErratic Testの原因特定 のために、「何を⽚付けてくれて いるか」知る必要がある • クラスの層ができるので、ある種 の「プロジェクトの仕様」を学習 する機会が発⽣する -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ •طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ •
ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ •Ϣχοτςετͷ ֶशίετൃੜ “Keep Tests Independent”のコスト評価 Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ •ܽؕͷૣظൃݟʹΑΔ मਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ -
© - BASE, Inc. +α テストの実⾏順序を指定する必要がある場合 • TestMethodA -> Bと順序を指定したいケースも
ありうる • PHPUnitでは、@depends アノテーション等で テストの依存関係を明⽰することも可能 Refs https://phpunit.de/manual/6.5/en/writing-tests-for- phpunit.html#writing-tests-for-phpunit.test-dependencies -
© - BASE, Inc. まとめ:不安定なユニットテストがあります > 実⾏順序で結果が変わるユニットテスト 不安定なユニットテストがあります 問題 障害
戦略 実⾏順序で結果が変わるユニットテスト “Keep Tests Independent” 判断 評価 . ⽋陥の早期発⾒による修コ スト削減 . 既存テスト維持コスト削減 . ユニットテストの学習コス ト発⽣ > < -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 • 実⾏順序で結果が変わるユニットテスト
• 相互依存するデータベースフィクスチャ -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 戦略 相互依存するデータベースフィクスチャ
Minimal Fixture / Standard Fixture -
© - BASE, Inc. “Standard Fixture” • “We reuse the
design of the test fixture across the many tests. • 複数のテストケースでフィクスチャレコード定義 を共有する戦略 Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 18. Test Strategy Patterns -
© - BASE, Inc. “Shared Fixture” “We reuse the design
of the test fixture across the many tests. -
© - BASE, Inc. “Minimal Fixture” • “Use the smallest
and simplest fixture possible for each test.” • テストケースごとにフィクスチャレコード定義を ⽤意する戦略 Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 18. Test Strategy Patterns -
© - BASE, Inc. “Minimal Fixture” “Use the smallest and
simplest fixture possible for each test.” ex. Larval: Factory, Ruby on Rails: FactoryBot -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 戦略 相互依存するデータベースフィクスチャ
Minimal Fixture / Standard Fixture 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する -
© - BASE, Inc. 不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 戦略 相互依存するデータベースフィクスチャ
Minimal Fixture / Standard Fixture 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する Minimal Fixture‧Standard Fixture 2つの戦略の⽐較から考える -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Standard Fixture”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • ⼀つの定義で済むのでフィクス チャの作成コストが削減 • ex. ユーザー情報のレコード準備 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Standard Fixture”のデメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • 複数テストケースで共有する分、 相互依存する • テスト間の独⽴性が低下 • 影響範囲を考慮に⼊れたテスト作 成が必要になる -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Standard Fixture”のデメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • フィクスチャレコードが⼤きくな りがちなので、テスト準備に時間 がかかる • テストの実⾏速度が低下する -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Standard Fixture”の評価 Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Minimal Fixture”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • テストケースごとの影響範囲なの で、最⼩限のフィクスチャレコー ドを⽤意すればいい • エッジケースのテストパターンを 作りやすい • ex. 「利⽤禁⽌ユーザー」 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Minimal Fixture”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • 既存テストコードが依存するフィ クスチャの影響範囲が明確 • 影響範囲が理解しやすい分、メン テナンスもしやすいテストフィク スチャになる -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Minimal Fixture”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • テストレコードが最⼩限なので、 テスト実⾏速度が(少し)早い -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Minimal Fixture”のデメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • “Standard Fixture”のメリットで もあるテストレコードの再利⽤ -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Minimal Fixture”の評価 Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ -
© - BASE, Inc. まとめ:不安定なユニットテストがあります 不安定なユニットテストがあります 問題 障害 戦略 相互依存するデータベースフィクスチャ
Minimal Fixture / Standard Fixture 判断 評価 . Minimal Fixtureのメリッ ト/デメリット . Standard Fixtureのメリッ ト/デメリット > < -
© - BASE, Inc. お品書き:このトークで取り上げる問題 • 意図が汲み取りにくいユニットテストがあります • 不安定なユニットテストがあります •
変更頻度が⾼いユニットテストがあります -
© - BASE, Inc. ERRORS! Tests: , Assertions: , Errors:
. ArgumentCountError: Too few arguments to function Hoge::getUserPoint(), passed and exactly expected -
© - BASE, Inc. 内部実装に依存したユニットテスト Private Method “getUserPoint”に対する ユニットテストが失敗していた "ArgumentCountError:
Too few arguments to function Hoge::getUserPoint(), passed and exactly expected” -
© - BASE, Inc. 内部実装に依存したテスト • 内部実装: 公開していない実装情報 • private
/ protected • 内部実装に依存しすぎるテストは、 “Fragile Test” (壊れやすいテスト)と呼ばれる • 振る舞いを変えない改善に対してもテストが反応 してしまう -
© - BASE, Inc. “Fragile Test” (壊れやすいテスト) • 修正した箇所と無関係なはずのテストが失敗しは じめる。
• いくつかの原因のうち、 “Overspecified Software” という状況となっている • テストコードで、テスト対象の振る舞いを過剰 に検証している。 Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 16. Behavior Smells -
© - BASE, Inc. 変更頻度が⾼いユニットテストがあります 変更頻度が⾼いユニットテストがあります 問題 障害 戦略 内部実装に依存したテスト
“Use the Front Door First” -
© - BASE, Inc. “Use the Front Door First”(最初に正⾯⽞関を使う) •
外部から利⽤することを期待する public インタ フェース と、内部のみからが期待される private インターフェース • テスト対象とは可能な限り、Front Door (public interface)を介した対話をする Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 5. Principles of Test Automation -
© - BASE, Inc. “Front Door”を介するための選択肢 . 既存の public インターフェースからテストする
. private インタフェースを public に引き上げる -
© - BASE, Inc. 変更頻度が⾼いユニットテストがあります 変更頻度が⾼いユニットテストがあります 問題 障害 戦略 内部実装に依存したテスト
“Use the Front Door First” 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Use the Front Door First”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔ ϝϯςφϯείετݮ • クラスの責務の⾒直しによる設計 改善 • メンテナンス性の⾼い動作コード へ -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Use the Front Door First”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔ ϝϯςφϯείετݮ • 動作コードの変更に対する変更頻度の減少 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Use the Front Door First”のデメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔ ϝϯςφϯείετݮ • テスト対象の内部処理は “ブラックボックス” として扱 いテストしすぎない • (外側から⾒た振る舞いを検証する) • 内部の private に複雑なロジックが詰め込まれている 場合、振る舞い保証が不⼗分な可能性も。 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “Use the Front Door First”の評価 Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔ ϝϯςφϯείετݮ -
© - BASE, Inc. まとめ:変更頻度が⾼いユニットテストがあります 変更頻度が⾼いユニットテストがあります 問題 障害 戦略 内部実装に依存したテスト
“Use the Front Door First” 判断 評価 . 設計改善によるメンテナン スコスト削減 . 既存テスト維持コスト . ⽋陥の早期発⾒による修正 コスト増加(の可能性) > < -
© - BASE, Inc. ERRORS! Tests: , Assertions: , Errors:
. Expectation failed for method name is equal to <string:getByCustomerId> when invoked time(s). Method was expected to be called times, actually called times. -
© - BASE, Inc. Mockが妨げるユニットテスト • 「顧客がbanされている」というケースでは TripRepository::getByCustomerId()は呼ぶ必要がなくなっ た。 •
しかし、ユニットテストは呼び出されることを期待している ため、テストは失敗する -
© - BASE, Inc. “Mock” を定義するためのxUTPによる語彙整理 Test Double: テスト固有の同等物 Mock:
テスト対象に適切に使⽤されているか検証 する Refs ॻ੶ʰxUnit Test Patterns: Refactoring Test Codeʱ / Chapter 23. Test Double Patterns -
© - BASE, Inc. このトーク内での “Mock” は「広義のMock Object」 Refs ॻ੶ʰςετۦಈ։ൃʱ
/ C ϢχοτςετपลͷࣝͷཧͱTDD֦ுͷࢼΈ • xUTPの語彙整理により、「広義のMock Object」‧「狭義のMock Object」を分けて議 論できるようになった • このトークでの “Mock” もTest Doubleの範囲を ざっくりと含める「広義のMock Object」とする -
© - BASE, Inc. 的確なエクスペクテーション Refs ॻ੶ʰ࣮ફςετۦಈ։ൃʱ / ୈ20ষ ςετͷΛௌ͘
“意図を明確にするためには、スタブとエクスペク テーション‧アサーションをきっちり区別するとよ い。” -
© - BASE, Inc. 区別するための指標:コマンド/クエリ Refs ॻ੶ʰ࣮ફςετۦಈ։ൃʱ / ୈ20ষ ςετͷΛௌ͘
ΫΤϦʹΞϩʔΞϯεɺίϚϯυʹΤΫεϖΫςʔγϣϯ • コマンドとは、 副作⽤を伴うことのある呼び出し • オブジェクトの外の世界を変化させる • ex. DBのレコード保存‧状態変化 • 複数回実⾏した場合、システム状態は違ったもの になる => エクスペクテーション -
© - BASE, Inc. 区別するための指標:コマンド/クエリ • クエリは、外の世界を変化させない • 何回呼んでも呼ばなくても構わない •
⇒ アローアンス Refs ॻ੶ʰ࣮ફςετۦಈ։ൃʱ / ୈ20ষ ςετͷΛௌ͘ ΫΤϦʹΞϩʔΞϯεɺίϚϯυʹΤΫεϖΫςʔγϣϯ -
© - BASE, Inc. 変更頻度が⾼いユニットテストがあります > Mockが妨げるユニットテスト 変更頻度が⾼いユニットテストがあります 問題 障害
戦略 Mockが妨げるユニットテスト “的確なエクスペクテーション” 判断 評価 . 戦略のメリット . を評価する . 戦略のデメリット . を評価する -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “的確なエクスペクテーション”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • テストコードのモックオブジェク トが適切にコントロールされる • 対象オブジェクトが他オブジェク トとどう協調するかがテストに よって⽰される -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “的確なエクスペクテーション”のメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔमਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • 動作コードの変更に対する変更頻度の減少 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “的確なエクスペクテーション”のデメリット Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔ मਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ • すべてエクスペクテーションにすると、過剰では あるがテスト対象オブジェクトの内部処理が”よ り”テストされる。 -
© - BASE, Inc. • ৽نςετ࡞ίετൃੜ • طଘςετҡ࣋ίετൃੜ • ςετ࣮ߦ࣌ؒͷͪίετൃੜ
• ࣗಈςετͷͨΊͷCIҡ࣋ίετൃੜ • Ϣχοτςετͷֶशίετൃੜ “的確なエクスペクテーション”の評価 Ϣχοτςετ ʹΑΔ ίετݮ Ϣχοτςετ ͷ ࡞ɾҡ࣋ίετ VS • खಈϢχοτςετͷίετݮ • ܽؕͷૣظൃݟʹΑΔ मਖ਼ίετݮ • υΩϡϝϯςʔγϣϯίετݮ • σόοάίετݮ • ઃܭվળʹΑΔϝϯςφϯείετݮ -
© - BASE, Inc. まとめ:変更頻度が⾼いユニットテストがあります > Mockが妨げるユニットテスト 変更頻度が⾼いユニットテストがあります 問題 障害
戦略 Mockが妨げるユニットテスト “的確なエクスペクテーション” 判断 評価 . ドキュメンテーションコス ト削減 . 既存テスト維持コスト削減 . ⽋陥の早期発⾒による修正 コスト削減 > < -
© - BASE, Inc. このトークの流れ . 取り上げる現場の問題 . ユニットテストの⽬的 .
現場の問題の整理と評価 .まとめ . 参考‧引⽤資料 -
© - BASE, Inc. まとめ • 課題の分析‧それに対する原則‧戦略は多くの⽂ 献で⽰されている • しかし、それらにはメリット‧デメリットがそれ
ぞれあり、絶対的な正解はない • 状況に応じてどの選択肢が適切か判断する必要が ある -
© - BASE, Inc. このトークの流れ . 取り上げる現場の問題 . ユニットテストの⽬的 .
現場の問題の整理と評価 . まとめ .参考‧引⽤資料 -
© - BASE, Inc. 参考‧引⽤資料 - トーク内で引⽤した書籍 • 『xUnit Test
Patterns: Refactoring Test Code』 • 『テスト駆動開発』 • 『実践テスト駆動開発』 • 『マイクロサービスアーキテクチャ』 • 『レガシーコード改善ガイド』 • 『プログラミング⾔語Go』 -
© - BASE, Inc. 参考‧引⽤資料 - トーク構築に寄与した書籍 • 『オブジェクト指向設計実践ガイド ~Rubyでわかる
進化しつづける柔軟 なアプリケーションの育て⽅』 • 『ソフトウェア‧テストの技法 第2版』 • 『プログラマが知るべき97のこと』 • 『リファクタリング 既存のコードを安全に改善する』 • 『Clean Code アジャイルソフトウェア達⼈の技』 • 『初めての⾃動テスト』 • 『Succeeding with Agile: Software Development Using Scrum』 • 『エキスパートPythonプログラミング 改訂2版』