Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
テスト駆動開発入門ハンズオン(後編)/TDD HandsOn 2
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Hiroki Iseri
June 12, 2011
Programming
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
テスト駆動開発入門ハンズオン(後編)/TDD HandsOn 2
Hiroki Iseri
June 12, 2011
More Decks by Hiroki Iseri
See All by Hiroki Iseri
生成AI活用でQAエンジニアにどのような仕事が生まれるか/Support Required of QA Engineers for Generative AI
goyoki
1
720
開発に寄りそう自動テストの実現
goyoki
3
4.3k
自動テストを活かすためのテスト分析・テスト設計の進め方/JaSST25 Shikoku
goyoki
3
2.9k
チームのテスト力を総合的に鍛えてシフトレフトを推進する/Shifting Left with Software Testing Improvements
goyoki
6
5k
チームのテスト力を鍛える
goyoki
4
3.5k
ソフトウェアテスト徹底指南書の紹介
goyoki
1
2.9k
プロダクト開発を成功させるためのソフトウェア品質保証のアプローチと技術/Software QA Approach for Puduct Success
goyoki
2
2.3k
チームのテスト力を総合的に鍛えて品質、スピード、レジリエンスを共立させる/Testing approach that improves quality, speed, and resilience
goyoki
5
3.8k
テスト分析入門/Test Analysis Tutorial
goyoki
12
7k
Other Decks in Programming
See All in Programming
Foundation Models frameworkで画像分析
ryodeveloper
1
590
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
150
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
210
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
450
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
480
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
420
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
170
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
540
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
580
その節約、円になってますか?
isamumumu
1
690
Claude CodeとAgentCore Gatewayを繋ぐ際の認証認可 / Authentication and authorization when connecting Claude Code with AgentCore Gateway
har1101
1
240
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
140
Featured
See All Featured
Facilitating Awesome Meetings
lara
57
7.1k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
200
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Designing Experiences People Love
moore
143
24k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
430
The agentic SEO stack - context over prompts
schlessera
0
860
The Invisible Side of Design
smashingmag
301
52k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.5k
Transcript
テスト駆動開発入門 ハンズオン講座(後編) Jissen.swtest 2011/6/11 井芹
おさらい 1. 最初にテストを書いて実行 (RED) 2. テストをパスするまでコード を実装(GREEN) 3. コードをきれいにする (REFACTOR)
これを繰り返しインクリメンタルに実装を進める RED GREEN Refactor
おさらい(壇上実践) • うるう年判定関数(グレゴリオ暦) – 西暦年が4で割り切れる年は閏年 – ただし、西暦年が100で割り切れる年は平年 – ただし、西暦年が400で割り切れる年は閏年
今回の概要 • TDDの周辺分野について – 今回は「TDDの効果拡大」をテーマに考え方やア プローチを紹介します
概要 • テストコードの運用 • テストコード運用上の問題 • テストによるコードの資産化 • テストコードのドキュメント化 •
レガシーコードでのTDD
TDDの テストコードの運用
テストコードの運用 • TDDでのテストの持続的効果 – 単体テスト容易性の確保 – 実装仕様の確保(Test as Documantation) –
自動化された回帰テスト環境の構築 • 継続運用の課題 – 単体テストとしての整理(前篇) – 運用環境の構築 – テストコードのメンテナンス
テストコードの運用フェーズ • 実装作業中、継続的かつこまめに – 常時実行される回帰テスト – 何度も何度も実行できるように自動化が協力に 推進される
継続的インテグレーション(CI) • 自動化されたインテグレーションを継続的に実行 1. インテグレーションを統合・自動化 • 単体テストを統合 2. インテグレーションの実行を自動化 •
インテグレーション用サーバを用意(Hudson有名) • 統合したインテグレーションを継続的に自動実行する – コミット時等。ナイトビルドよりもっと頻繁に – 継続的ですばやいフィードバックを実現
単体テスト運用環境 作業用PC 構成管理サーバ DB関連テスト ストレステスト 規格バリデーション コミット 更新・ 自動実行 更新・
自動実行 更新・ 自動実行 制約のあるテストを分散運用することで SlowTest問題や高コストを回避する
実行の分散方針 • TDDのテストは軽快に • 「実行に0.1sもかかる単体テストは、遅い単体テストである」 (レガシーコード改善ガイド) • Slow Test問題:時間のかかるテストのせいでTDDの効率が落ちる •
重い/制約のあるテストはサーバ側、自動化へ – 時間がかかる/特定環境依存/高コスト • TDDでは必要なテストのみ実行すればよい – 全テスト実行はサーバ側へ
テストコードの運用まとめ • TDDのテストの継続的効果 • 単体テスト運用環境の軸 • 構成管理システムと単体テスト • 継続的インテグレーション •
テスト負荷の分散
テストコード運用上の問題
テストコード運用上の問題 • TDDのテストは一般的に継続利用されるため: – メンテナンスしないと品質悪化 – 保守性が悪いとレガシー”テスト”コードとして開発 の足を引っ張ってくる
Fragile Test • 製品コードの変更に弱いテスト – 些細なコード変更で大量のテストが失敗 – 仕様や機能とは無関係な変更でテストが失敗 • リファクタリングやCover
& Modifyのコストを 増大させる(TDDはリファクタリングを推進するはずなのに・・・) • TDDでのエントロピー問題
Fragile Test void test_1() { Hoge hoge = new Hoge(…);
… } void test_2() { Hoge hoge = new Hoge(…); … } void test_3() { Hoge hoge = new Hoge(…); … } …. void test_100() { Hoge hoge = new Hoge(…); … } void test_101() { Hoge hoge = new Hoge(…); … } void test_102() { Hoge hoge = new Hoge(…); … } テストメソッドがHogeクラスに過依存 Hogeクラスのコンストラクタが変更されたら大量のテスト失敗が発生
Fragile Test対策 • 3つの方針 – テスト対象への過依存を避ける – テストの変更可能性に基づいてテストを設計する – テストの保守性に基づいてテストコードを設計する
テストのテスト対象への 過依存を避ける • テストにおけるテスト対象への4つの過依存 – Interfaceへの過依存 – Behaviorへの過依存 – Dataへの過依存
– Contextへの過依存
テストのテスト対象への 過依存を避ける • 対策:過剰な依存部を取り除く – 重複するテスト対象呼び出しはないか? →重複を関数やクラスでまとめる – テスト対象の内部に過剰に依存していないか (リフレクションなどで無理に内部にアクセスしていないか)
→パブリックなインターフェースでアクセスする →問題があればモジュール設計を再検討する – 一部の過依存がまわりを巻き込んでいないか →依存部をラッピングする
対策例:Creation Method public void testHoge_first() { Piyo piyo = new
Piyo(1, 2, 3); ... } public void testHoge_second() { Piyo piyo = new Piyo(4, 5, 6); ... }
Creation Method public void testHoge_first() { Piyo piyo = createUniquePiyo();
... } public void testHoge_second() { Piyo piyo = createUniquePiyo(); ... } public Piyo createUniquePiyo() { return new Piyo(generateValue(), generateValue(), generateValue()); } 「Customer」という製品コードのへの依存部が削減された
テストの変更可能性に 基づいてテストを設計する • 単体テスト設計のアプローチ – 仕様ベース • 仕様分析によって、仕様保障を目的とするテストを設 計する –
構造ベース • 構造分析によって、構造を網羅するようにテストを設 計する – 経験ベース • エラー推測、経験を元にテストを設計する
単体テスト設計の アプローチの扱い • 仕様ベースのテスト設計を重視 不足を構造ベースのテスト設計で補う – 構造はリファクタリングで変化する • 構造への過依存はFragile Testとなり制約
に – 構造ベースで網羅的に設計したテストはナマモノ
アプローチの扱い int hoge(int input) { return input * 2; }
Int型は仕様か、構造的な制約か
構造の変更可能性 • 構造ベースでも変更可能性に程度がある – 「仕様としての構造」 – 暫定実装 構造の変更可能性 大 小
暫定実装 内部メンバ ライブラリ モジュール等 のインタフェース 規格化された構造
構造の変更可能性 • 構造の変更可能性の2軸 – 時間軸方向の変更可能性 – 構造軸方向の変更可能性 • Ex)時間軸方向の変更可能性 •
短期(一時的) – 暫定使用、実装過程での仮実装など • 中期 – 機能、各部モジュールなど • 長期 – 公的規格、標準規格、根幹的なアーキテクチャなど
時間軸方向の変更可能性 • 長期的に安定するものから網羅性を高める – Ex)規格仕様は作りこんでV&V手段として使えるよ うにする • 「SQLiteのテストコードは4567万8000行。本体のコード は6万7000行」 –
一時実装のテストコードも一時実装 • 作りこむとFragile Testの原因となる
アーキテクチャ設計による 変更可能性の管理 • TDDはアーキテクチャ設計で支える – 外部設計 • テスト容易性を阻害するDOCを局所化する – 内部設計
• テスト容易性を確保する • TDDのインプットとなる各モジュールの仕様を定義する • 変更可能性対策をアーキテクチャに盛り込む • Ex)タイミング設計:単体テストを阻害しないように
テストコード運用上の問題 • Fragile Test • 変更可能性の観点 • TDDとアーキテクチャ設計
テストによるコードの資産化
TDDによる実装アプローチの変化 • TDDで書かれたコードは全体にわたって – 単体テストが確保される – 単体テスト容易性が確保される • 自動化された回帰テスト環境が Cover
& Modifyのアプローチを実現する
Cover & Modify • 手順 – 1 パスする回帰テストを確保する – 2
テストが成功する状態を保ちつつ、コードを変 更する
Edit & Pray • 「変更して動かしてみる」 • Cover & Modifyの対比となる実装アプローチ 世の中で一般的
• 手順 – 1 コードを変更する – 2 うまく動くように祈る
Cover & Modify • 「テストで保護(Cover)して修正(Modify)する」 • テストで修正・変更の影響範囲を絞り込む – コードの変更作業が安全に –
保守開発で推奨される実装アプローチ
Cover & Modify[実演] • Case 4 で1234を返す
Cover & Modify例 • リファクタリング – 1 機能を保護するテストを確保する – 2
テストがパスする状態を維持しながら、コード を変更する
Cover & Modify例 • TDDによる機能変更 – 1 変更対象の回帰テストを書く – 2
TDDのサイクルへ • 変更機能のテストを書く(Red) • 実装する(Green)
Cover & Modify[課題] • うるう年判定(前回の課題) • 追加仕様: – 負の値が入力された場合はfalseを返す
TDDとCover & Modify • TDDとCover & Modifyは親和性が高い – コードをテストに対して最適化されるため、コード のテスト容易性が高まる
• テストで保護しやすくなる – テストコードが確保される – そもそもCover & ModifyがTDDのようなもの
コードの資産化 • TDDはコード資産化効果を促進する – TDDによりCover & Modifyを実現 • コードの保守性が大きく改善 •
コードの資産化が促進される
コードの資産化まとめ • Edit & Pray • Cover & Modify –
リファクタリング – 機能追加 • TDDのコード資産化効果
テストコードのドキュメント化
テストコードのドキュメント化 • 「テストコード=実装仕様」という思想 – Test as Documantation – TDDでのテスト設計で目指される理想の1つ –
テストコードを動く実装仕様書として活用する – バグ出し、品質保証ではなく、仕様記述という目 的でテスト設計を行う
Example Driven Development • EDD。実例駆動開発。TDDの1種 • EDDでのテスト=テスト対象の使い方の実例 • テストファーストが苦手な人のためのプラク ティスとして有効
• 手順: – 最初に実装コードの使い方の実例を考える – 実例をテストで表現する – 以後はTDDのサイクルへ
Example Driven Development [課題] • 演算器 – 整数を入力できる – 入力した整数の計算結果を出力できる
Behavior Driven Development • BDD。ビヘイビア駆動開発。TDDの派生物 • BDDのテスト=テスト対象のふるまい仕様 – ふるまい仕様でテストを語れるようにする →テストファーストにユーザやドメイン専門家を巻
き込めるようにする。それらからの要求取得→開 発リリースのサイクルを高速化する
BDDフレームワーク • 自動テストフレームワークの一種 • xUnitの設計に基づくものが多いが、命名や 構造がBDDの思想に合わされている • 仕様記述のためのDSLを提供するものもある
BDDフレームワーク • JUnit – assertEquals("hoge name", hoge.getName()); – assertEquals(16, hoge.getAge());
• JDave(BDDフレームワーク) – specify(hoge.getName(), must.equal("hoge name")); – specify(hoge.getAge(), must.equal(16));
Behavior Driven Development [課題] • 演算ライブラリ
ドキュメントとしてのテストコード • Characterization test • Test All-at-Onceによるフィーチャ分析
Characterization test(仕様化テスト) • コードのふるまいや用例を、パスするテストと して表現する – 仕様表現、コードの理解が目的 – 満たすべき仕様として回帰テストとして作用する
Characterization test(仕様化テスト) • Characterization testによるコード解析 – 1 適宜の入出力で解析対象のテストを書く(最 初は失敗させる) –
2 テストがパスするまで入出力の値を調整する • テスト失敗したら期待値を実行値に置き換える • 例外が発生したら例外テストに置き換える – 目的が達成されるまでこれを繰り返し、テストを 継ぎ足していく
Characterization Test[課題] • 前回の課題のCharacterization Testを用意す る
Test All-at-Onceによるフィーチャ分析 • 実装対象に求められるフィーチャをテストメ ソッドとしてすべて洗い出す – テストメソッドはスケルトン。かつignore設定 – TDDの中で1つ1つignore指定除去&スケルトン実 装をすすめ、最終的にTDDのテストコードがすべ
てのスケルトンを内包するようにする – 最終的に、洗い出したスケルトンセットが整合性 の取れたフィーチャ実装となる
Test All-at-Onceによるフィーチャ分析 [実演] • うるう年判定関数で実施
テストコードのドキュメント化まとめ • TDDとテストコードのドキュメント化 • EDD/BDD • Characterlization Test • Test
All-at-Onceによるフィーチャ分析
レガシーコードでのTDD
レガシーコードでのTDD • 単体テスト容易性が低いコードではTDD実行 前にコードの修正が必要 – Cover & Modifyから外れた修正 – コードを汚くしてしまう修正
通常のTDD 1. テストを書く 2. テストをパスするコードを書く 3. リファクタリングする
レガシーコードでのTDD 1. (よく考える) 2. 依存性を排除する 1. 変更点を洗い出す 2. テストを書く場所を見つける 3.
依存性を取り除く 3. テストを書く 4. テストをパスするコードを書く 5. リファクタリングする
依存性の排除 • リスクを許容するとしても、リスクを抑える – 低リスクなツール支援が使えるなら活用 – 低リスクな変更手段があるなら活用 • private→protected •
finalを削除する – 上位のテストで補完 • リスクにある変更は慎重に考える – “よく考える” – スクラッチリファクタリングなどでイメージを固める
スクラッチリファクタリング • テストや制約を一切無視して自由にリファクタ リングする – テストは記述しない – リファクタリング結果は使い捨て • 目指している結果が妥当かどうか、実際に
コードを書いて評価する
依存性の排除例 (コンストラクタのパラメータ化) public Hoge { private MissileCtrl missileCtrl; public Hoge()
{ missileCtrl = new MissileCtrl (): } public void piyo() { …. missileCtrl.発射(); …. missileCtrl.発射2(); …. } …. }
依存性の排除 (コンストラクタのパラメータ化) public Hoge { private MissileCtrl missileCtrl; public Hoge(MissileCtrl
missileCtrl) { this.missileCtrl = missileCtrl; } public Hoge() { thils(new MissaileCtlr()); } public void piyo() { missileCtrl.発射(); } …. } Hoge(new FakeMissileCtrl());
レガシーコードでのTDDまとめ • レガシーコードでのTDDのステップ • 依存性の排除 – コンストラクタのパラメータ化 • スクラッチリファクタリング
レガシーコードでのTDD[課題] • 前回課題のBookList改変版
最後のまとめ • 取りあえず覚えてもらいたい要点 – 継続的インテグレーション – Fragile Test – Cover
& Modify – レガシーコードでのTDD – テストコード=ドキュメントとする考え方