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
階層化自動テストで開発に機動力を
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
ICKX
July 18, 2025
Programming
880
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
階層化自動テストで開発に機動力を
ICKX
July 18, 2025
More Decks by ICKX
See All by ICKX
AIの揺らぎに“コシ”を与える階層化品質設計
ickx
0
320
Symfonyの特性(設計思想)を手軽に活かす特性(trait)
ickx
0
160
検索条件にCRITERIAを
ickx
0
88
「兵法」から見る質とスピード
ickx
1
520
あなたの知らない新潟
ickx
0
93
香川にはTyrellがあるからね
ickx
0
420
品質が高いコードって何?Rev2.1
ickx
2
1.1k
品質が高いコードって何?
ickx
7
4.9k
【PHPerKaigi2021】PHPでCSVを安心して扱うために
ickx
4
3.3k
Other Decks in Programming
See All in Programming
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
250
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
dRuby over BLE
makicamel
2
330
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
170
Modding RubyKaigi for Myself
yui_knk
0
910
Swiftのレキシカルスコープ管理
kntkymt
0
220
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.4k
New "Type" system on PicoRuby
pocke
1
730
運用エージェントは "作る" から "育てる" へ - 記憶と自己進化の3層設計パターン / self-evolving-agents-three-layer-agent-design
gawa
12
3.6k
ふつうのFeature Flag実践入門
irof
7
3.6k
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
330
Featured
See All Featured
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
140
Fireside Chat
paigeccino
42
3.9k
Producing Creativity
orderedlist
PRO
348
40k
A designer walks into a library…
pauljervisheath
211
24k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4k
Writing Fast Ruby
sferik
630
63k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
BBQ
matthewcrist
89
10k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
What's in a price? How to price your products and services
michaelherold
247
13k
Transcript
階層化自動テストで 開発に機動力を 同人ソフトサークル Project ICKX 若葉 章 @effy_staffs (EFFY開発チーム)
自己紹介 • 若葉 章(わかば あきら) • 2010年~ 同人ソフトサークル project ickx
• プロデューサー / 営業 / インフラ / サーバサイド... / ゲームの実開発以外全部 • 本職はスタッフエンジニアっぽいこともするphpエンジニア • php続けてもうすぐ25年 php3の頃からお世話になっています • 最近の趣味は自転車とコーヒーとアマチュア無線 • tyrell iveで京阪や徳島から高松まで走ったり、icom ic-705やID-52で移動運用試したり • ボトルゲージ用のアルミステーやドリッパーホルダの自作を始めましたもうだめだ • Nintendo Switch で『VERTICAL STRIKE ENDLESS CHALLENGE』販売中 • Qiitaで『phpで高速に・省メモリ・確実に日本語csvを扱う方法』公開中 https://qiita.com/wakabadou/items/84b48ca12f25fb2fb69c 「composer require fw3/streams」をよろしくね。 「composer require tacddd/tacddd」もよろしくね。 「composer require bypassflow/crypt 」もよろしくね。
None
None
宣伝 PHPerKaigi2021で発表した「PHPでCSVを 安心して扱うために」にて紹介した、SJIS CSVを直接扱えるライブラリ “fw3/streams “ 最新版にてZIPファイル内のCSVファイルを ”そのまま直接”扱えるようになりました。 ぜひ使ってみてね。
こんな感じ。 CSVの設定はふつう NoRewindIterator万歳!!
宣伝 最近、bypassflowと名付けたPHP8.4以降向けの ライブラリ開発に着手しました。 現在はcryptのみリリースしています。 同じ条件でも毎回違う結果が出るのに適正に検証できるハッシュ 同じ条件でも毎回違うバイナリが出力される暗号化処理 来月あたりに強力なオブジェクトコレクションを リリースする予定なのでお楽しみに。
資料1 PHPカンファレンス関西2024やPHPerKaigi2024で 発表した”「“品質”が高いコード」って何?”を 読むとより理解が深まります
資料2 PHPカンファレンス新潟2025で発表した ”「兵法」から見る"質とスピード"”を 読むとより理解が深まります
用語・原則
“テスト”
• リスクベースのアプローチの下で静的および動的技法を 用いソフトウェアが仕様や要求事項を満たしていることを 検証(Verification)妥当性確認(Validation)する 一連のプロセス • 有限のテストケースによる実行や解析を通じて欠陥を検出 し、品質情報を提供するもの ISO/IEC/IEEE 29119-1:2022で定義される
ソフトウェアテストでは
“品質”
“品質”とは “対象”に“本来備わっている特性”の 集まりが“要求事項”を満たす“程度” ISO 9000 (JIS Q 9000:2015)
ISO 25000で定義される “ソフトウェアの品質”では 明示された条件下で使用するとき、 明示的ニーズ又は暗黙のニーズを満たす ためのソフトウェア製品の能力 ISO/IEC 25000:2014 (JIS X
25000:2017)
つまり“品質”とは “要求を満たしていること”
“高品質”
“高品質”とは • “定められた要求事項”に対して“要求を満たしている”こと です。 • 超過でも未満でもなりません。 • めっぽう忘れられがちですが、 未満だけでなく、超過もダメです。
“高品質” を達成するには?
レイヤごとに要求を 明確化しそれを達成する
単一責任原則
モジュール、クラスまたは関数は、 単一の機能について責任を持ち、 その機能をカプセル化するべきである
開放閉鎖原則
ソフトウェア要素は、 拡張に対しては開いており、 修正に対しては閉じているべきである
テストにおける 単一責任原則
テストは単一のスコープについて 責任を持ち、その検証・妥当性確認を カプセル化すべきである
テストにおける 開放閉鎖原則
テスト内容は 階層の追加に対しては開いており、 修正に対しては閉じているべきである
階層化自動テストで 開発に機動力を
Webサイトを対象とした 今までのテスト階層
• セッション・永続化を伴う複数URLへの一環した操作 • リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストに対するレスポンス • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て
• クラス、関数に対する入力と出力
• セッション・永続化を伴う複数URLへの一環した操作 • リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストに対するレスポンス • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て
• クラス、関数に対する入力と出力 E2Eで カバー xUnitで カバー
E2Eのカバー範囲が巨大すぎて 出力に関係する変更があった場合 膨大な修正が生まれる訳です
そもそもこれ “開放閉鎖原則” に即していないんですよね 修正のたびに別階層に影響でる訳だし
これがあるので 「E2Eは必ず破綻する」 などと言われてきたわけです
テストを 境界づけられたコンテキスト として整理します
そこで
テストの関心事を テストで見るべきもので分割する
• 状態 • 特定条件における出力内容を状態と定義します • テストとして関心事は特定条件における出力内容の妥当性 • テスト開始条件は固定され、結果には冪等性を要求します • そのため、前後URLなどのフローに関する内容は関知しません
• フロー • 関連する複数の状態を横断するものをフローと定義します • テストとしての関心事は適切にフローを流せるか • その際のチェックポイントとして一部の状態をテストすることも ありますが、チェックポイント以外の状態は関知しません
• フローとして見るべきもの • セッション・永続化を伴う複数URLへの一環した操作 • リクエスト受け付けから出力までの処理コールツリー • 状態として見るべきもの • 単一URLリクエストに対するレスポンス
• 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力
• フローとして見るべきもの • セッション・永続化を伴う複数URLへの一環した操作 • リクエスト受け付けから出力までの処理コールツリー • 状態として見るべきもの • 単一URLリクエストに対するレスポンス
• 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 E2Eで カバー xUnitで カバー
それは今まで通りのE2Eと xUnitでカバーしていた事では?
では別の関心事で整理してみます
テストの関心事を ”完結できる単位”で分割する
• 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 • 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス • 変数値の確認で完結できる
• リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力
フローとして見るべきもの 状態として見るべきもの 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス 変数値の確認で完結できる •
リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 マトリクスにするとこんな感じ
フローとして見るべきもの 状態は強く意識せず、フローだけをテスト 状態として見るべきもの フローは意識せず、状態だけをテスト 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス
変数値の確認で完結できる • リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 関心事を”テストで見るべきもの”にした場合
フローとして見るべきもの 状態は強く意識せず、フローだけをテスト 状態として見るべきもの フローは意識せず、状態だけをテスト 複数リクエストの集約が必要 E2E以外では実現困難 • セッション・永続化を伴う複数URLへの一環した操作 単一リクエストで完結できる 状況によりE2E、xUnit使い分け
• 単一URLリクエストに対するレスポンス 変数値の確認で完結できる xUnitのみで完結できる • リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 関心事を”テストを完結できる単位”にした場合
どこに注目する必要があって どのようにすればいいか を考えやすくなりました
また、テストを実施する手段を 適材適所しやすくなりました
完結できる単位に注目すると テスト階層が見えてきます
テスト階層に期待される責務も 明確になってきます
• 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 • 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス • 変数値の確認で完結できる
• リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 フローが妥当に流れること
• 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 • 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス • 変数値の確認で完結できる
• リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 状態が妥当であること
• 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 • 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス • 変数値の確認で完結できる
• リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 フローが妥当に流れること
• 複数リクエストの集約が必要 • セッション・永続化を伴う複数URLへの一環した操作 • 単一リクエストで完結できる • 単一URLリクエストに対するレスポンス • 変数値の確認で完結できる
• リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て • クラス、関数に対する入力と出力 状態が妥当であること
状況が整理された所で テスト階層の詳細を 見ていきましょう
セッション・永続化を伴う 複数URLへの一環した操作
• E2Eを適用せざるを得ない階層 • リクエストパラメータの管理や描画内容の検証 を考えると、E2E以外での対応は非現実的 • なんでもできるから、なんでもやってしまう そのせいで地獄のメンテが発生します • そう思い込まれがちですね
このテスト階層に期待される責務は?
フローが妥当に流れること
• URLをまたぐフローにのみ関心を持ちます • URLごとの詳細な状態は他テスト階層で 保証されます • 結果、フロー変更の影響を局限できます • MPAならとてもシンプルですね •
入力 => 確認 => 完了 => 結果確認 の流れだけ • 入力で入れた内容が確認で出力され • セッションに入った内容が完了で反映され • 反映された内容が結果画面で確認できること
ここでの肝は各ページでの細かい内容の 検証・妥当性確認を行わないことです
見るべきは妥当に遷移できたかどうかと 遷移結果としてユニークな状態のみです
E2Eテストが爆発しがちだったのは、 期待される責務である フローが流れること 以上のことを詰め込んでいたから
フローが流れるというのは ビジネス上重要な価値を持つ処理 が流れている事も指します
フローのみに関心を持てれば ビジネス上優先すべきテスト対象なのか で優先順位付けを行いやすくなるわけです
優先順位付けを行いやすくなるということは 判断の迷いが弱くなり意思決定も速くできるため 開発プロセスのリズムがよくなり テンポを速めることにつながります
では各URLごとの 詳細な状態の確認は どうする?
適切な責務を 担う階層に 委譲しよう!
単一URLリクエストに 対するレスポンス
• 一般にE2Eが適用される階層 • 負担感が爆増するのは大抵の場合ここのせい • 全体を通すE2Eで巻き取れてしまうため 単体で実行する意味がない • そう思い込まれがちですね
このテスト階層に期待される責務は?
入力検証、出力・表示内容が ブラウザ描画時点の内容として 妥当であること
• そのURLで完結する表示状態にのみ関心を持ちます • フローや変数の状態は他テスト階層で保証されます • 結果、表示内容変更の影響を局限できます • 特定のHTTPリクエストに対して、妥当なレスポンスで あるかを見ることで冪等性のあるテストをします •
ページ遷移に伴う外乱がなく、純粋な リクエスト・レスポンスに関心を集中できます
単一URLリクエストにおける 変数割り当て
• 一般にE2Eが適用される階層 • 負担感が爆増するのは大抵の場合ここのせい • レンダリングするんだからE2Eでなければだめ • そう思い込まれがちですね
このテスト階層に期待される責務は?
出力前段階として 割り当てられている 変数が妥当であること
• 描画に利用する変数の状態のみ関心を持ちます • フローやブラウザでの描画、変数生成手段は 他テスト階層で保証されます • 結果、アサイン内容変更の影響を局限できます
レンダリングする内容、 どうやって渡してますか?
一般的なフレームワークを利用している場合、 Renderインスタンスに直接変数アサインか View Modelオブジェクト経由が多いです
そう、この時点で変数なんですよ つまりxUnit適用できるな?
今までE2Eに対応を強制していた 検証内容をより早い段階へ委譲させる ことが出来ました
ストレージ以外の大がかりな実行準備を 必要としないため、比較的軽率に実行 出来るのも利点です
また、その気になればEC CUBE2などの 旧いプロダクトであったとしても 適用できる余地があります というかやった あれはRender内でexitしてるのでそのあたりの つじつま合わせが大変ですが
単一URLリクエストに おける検証処理
• 一般にE2Eが適用される階層 • 他の階層で吸収されたり、されなかったりと 曖昧になりがち • フォーム入力とブラウザ出力なんだから E2Eでなければだめ • そう思い込まれがちですね
このテスト階層に期待される責務は?
HTTPリクエストを入力値として 値の文字列表現が 受入仕様に対して妥当であること
• 入力値の文字列表現が受入仕様に対して妥当か どうかのみ関心を持ちます • フローやブラウザでの描画、変数生成・割当 手段は他テスト階層で保証されます • 結果、受入仕様変更の影響を局限できます
ただし…
• 入力値検証処理のみを切りはがせる環境である 必要があります • SymfonyならTypeTestCaseで検証できるが 単一URL単位でのリクエストとして表現する のが手間
かつて私が提供した環境では RequestModelという概念を用意し そのリクエストが成立するために必要なこと 全てが妥当であることを保証していました
リクエスト受け付けから出力までの 処理コールツリー
• 他のテストが結果として巻き取っている階層 • 滅法バグが出る原因の一つ • 特に引数・返り値の変数型周り • インターフェースなり値オブジェクトなりで 意味安全をガチガチに固めてあればPHPStan などで静的解析としてテストが可能に
このテスト階層に期待される責務は?
特定コード地点からの呼び出し フローが妥当に流れること
フローが妥当に流れること
• マーチンの開放/閉鎖原則をうまく適用できていると、 インターフェースの呼び出しツリーをフロー、 具象の関心事を状態として定義する事ができます • URLリクエストに対する関心事、具象の関心事は 他テスト階層で保証されます • 結果、呼び出しツリーの変更の影響を局限できます
クラス・関数に対する入力と出力
• 一般にxUnitが適用される階層 • ここについては議論の余地がありませんね • テクニックとしてはJIG(治具)と見立て 作業中のリグレッションテスト機能として 割り切ると扱いやすくなります
このテスト階層に期待される責務は?
クラス・関数への入力が 出力時に状態として 妥当であること
• プログラミングインターフェースへの 入力から得られる出力状態にのみ関心を持ちます • 呼び出しフローは他テスト階層で保証されます • 結果、クラス・関数の仕様変更影響を局限できます • 使われ方の特性上、限定条件に特化した検証を 実施しやすいため、適切に作りこむと”追跡が面倒”な
不具合を抑止しやすくなります
ここまでのテスト階層にない テスト対象が発見された場合は?
コンテキストが 増えただけなので 適宜増やせば宜しい
逆もまたしかりで 例えばリクエスト検証処理は 実装都合で事実上実現不能ならば 減らしてしまえばいい
ただし、テストプロセスに対して 要求される事項を誤って削らないよう 注意が必要です
結びに
階層化自動テストとは • 境界付けられたコンテキストに応じてテストを分割する • テストの関心事を見るべきものと完結できる単位で分割する • テストで見るべきものをフローと状態に分割する • 階層テストはそれぞれ独立して機能する •
階層テストはプロセスに要求されるコンテキストの有無で増減する • ツールの謳う使い方に囚われない • 上記を満たし、実施される自動テストが階層化自動テストである
階層化自動テストを 導入するメリット
• テスト範囲と責務の明確化 • 修正・メンテコストの低減 • 開発プロセスのリズム・テンポ向上
階層化自動テストを導入することで テスト対象が明確になるため 高機能なテストを低負担で 実現しやすくなります
• セッション・永続化を伴う複数URLへの一環した操作 • 単一URLリクエストに対するレスポンス • リクエスト受け付けから出力までの処理コールツリー • 単一URLリクエストにおける検証処理 • 単一URLリクエストにおける変数割り当て
• クラス、関数に対する入力と出力 画面遷移 のみ担当 画面描画 のみ担当 プログラムコール ツリーのみ担当 HTTP入力検証 のみ担当 アクションが生成 する変数のみ担当 処理の入出力 のみ担当
各工程において実施すべきテストを 適切に局限できるため 各工程で必要とされるテストを より早く完了させる事が出来ます
またいつそのテストが実施されるのか 工程単位でここまでは保証済みが 自明となるため 業務プロセスのリズムを 取りやすくなります
• セ ッ シ ョ ン ・ 永 続 化
を 伴 う 複 数 U R L へ の 一 環 し た 操 作 • 単 一 U R L リ ク エ ス ト に 対 す る レ ス ポ ン ス • リ ク エ ス ト 受 け 付 け か ら 出 力 ま で の 処 理 コ ー ル ツ リ ー • 単 一 U R L リ ク エ ス ト に お け る 検 証 処 理 • 単 一 U R L リ ク エ ス ト に お け る 変 数 割 り 当 て • ク ラ ス 、 関 数 に 対 す る 入 力 と 出 力 リリース前 受け入れ前 PR前 コミット 単位 作業 単位 作業 単位 上書き 保存単位 テストプロセスフロー
おしまい
appendix データ設計
自動テストを設計するにあたり 甚大な影響を与えるのがデータです
理想を言えば全てモックで完結できる 簡潔なデータ設計になっていると良いのですが そんな都合の良い状況はあまりありません
現実としてはストレージを利用して テストした方が速いし正確とかあるある
現実に負けてストレージに依存するテストを 設計する場合に問題になるのが 初期化に莫大な時間を 要求するマスタデータ
ECサイトならば 不正住所情報
これに対する対処として DBを分割する選択肢があります
MySQLなら同一接続先内で 別データベースを作るだけで対応できます 仮にリレーションが必要だった場合 DB名.テーブル名で指定する事が出来ます
PostgreSQLやSQLiteの場合は… 流石にリレーションきびしい…
¥e