$30 off During Our Annual Pro Sale. View Details »

法人支出管理領域におけるソフトウェアアーキテクチャに基づいたテスト戦略の実践

Avatar for ogugu ogugu
December 06, 2025

 法人支出管理領域におけるソフトウェアアーキテクチャに基づいたテスト戦略の実践

Avatar for ogugu

ogugu

December 06, 2025
Tweet

More Decks by ogugu

Other Decks in Technology

Transcript

  1.   2 経歴 • オプティムに新卒⼊社 ◦ Android開発を経験した後、2年⽬からQA に転⾝ • freeeに中途⼊社

    ◦ 同期マイクロサービスのQAを担当し、同期 ジョブのintegration testを導⼊ ◦ 決済プロダクトのQA Leadを担当し、テス トアーキテクチャの考え⽅を導⼊ ◦ 現在は⽀出管理領域のQA TechLeadを担当 好きな⾷べ物 • カレー 苅⽥蓮(ren) QAエンジニア Ren Karita プロフィール画像の トリミング⽅法
  2. 3 • 2018年 ヤフー 新卒入社
 ◦ ヤフーショッピングのリアーキテクトに従事
 • 2021年 freee

    中途入社
 ◦ 人事労務→SRE→支出管理領域のTL
 ◦ 2025年から業務委託に切り替え、開発支援
 • 2025年 スカイゲートテクノロジズ 
 ◦ 防衛テックにて VPoT を務める
 ◦ 国防製品やゼロトラストセキュリティ製品の開発とテ クニカルリード
 小倉 陸 (ogugu)
 支出管理開発本部 業務委託 (開発支援)
 スカイゲートテクノロジズ株式会社 VPoT
 @ogugudayo

  3. 7 大規模SaaS開発におけるテストの課題
 ソフトウェアとテストのアーキテクチャ不整合 
 • 費用対効果の悪いテスト
 ◦ 依存が多い “調整ロジック” に

    Unit Test を適用し、大量のテストダブルに疲弊
 • テストが容易でないソフトウェア設計
 ◦ Unit Test が書きづらいレイヤーに詳細なロジックが実装されている
 • ソフトウェア設計に応じたテスト分解ができない
 ◦ 手動テストのシナリオをそのまま E2E に書き起こして Fat な E2E になる
 ◦ マイクロサービス間の非同期連携を E2E でテストして Flaky になる
 • 遅くて不安定なテスト
 ◦ E2E や Integration Test で Parametrized な Test を実施して時間がかかる

  4. 8 大規模SaaS開発におけるテストの課題
 テストの定義における知識や解釈の不一致 
 • 最もよく知られた Test Level = Unit,

    Integration, E2E は定義が曖昧
 ◦ Integration Test はモジュールの結合か、物理的分離されたシステムの結合か?
 ◦ どこまで結合していたら Unit Test ではなくなるのか?
 ◦ バックエンドコンポーネントのエンドツーエンドなテストは E2E と呼んでいいのか?
 • Test Size はインフラストラクチャの制約の視点による分類
 ◦ ソフトウェアアーキテクチャの視点による分類ではない
 ◦ そもそもQAは知っているが、プロダクト開発者はあまり知らない

  5. 12 形式化の事前準備
 プロセス境界と外部 I/O による形式化 
 プロセス境界 :
 • テストコードとアプリケーションコードが同一プロセスで実行されるか?

    
 • = “テストがどのように実行されるか ” の本質
 • 同一プロセスならば早く安定、別プロセスならば遅く不安定
 
 形式化: 
 プロセス閉包: 𝑃 T ﹦𝑃 A 
 プロセス分離: 𝑃 T ≠ 𝑃 A 
 • 𝑃 T : テストコード 𝑇 を実行するプロセス
 • 𝑃 A : テスト対象のアプリケーション 𝐴 を実行するプロセス

  6. 13 形式化の事前準備
 プロセス境界と外部 I/O による形式化 
 外部 I/O: 
 •

    アプリケーションの実行プロセスがその外側の計算資源にアクセスするか? 
 • = “テスト対象がどのように振る舞うか ” の本質
 • 外部 I/O が発生すれば遅く不安定になる (例: ネットワーク I/O, ファイル I/O)
 • 多くのアーキテクチャパターンでは、外部 I/O が発生する箇所をレイヤーとして分離 
 
 形式化:
 プロセス 𝑃 に対する外部リソースの集合を 𝛀 𝑒𝑥𝑡 とする。
 𝛀 𝑒𝑥𝑡 = 𝛀 \ (𝑃 ∪ 𝑀 P )
 • 𝛀 : 計算機システム全体の全リソース集合
 • 𝑀 P : プロセス 𝑃 に対して割り当てられた仮想メモリ空間
 ここで、関数 𝑓 を実行したとき、 𝛀 𝑒𝑥𝑡 に属する外部リソースへの読み書きが
 発生する場合、𝑓 は外部 I/O を伴う関数である と定義する。
 

  7. 14 形式化の事前準備
 外部入力と外部出力 
 外部 I/O は情報の流れる方向 によって、「外部入力」と「外部出力」に分けられる。
 ここで、𝑆 𝑖𝑛𝑡

    : プロセスの内部状態, 𝑆 𝑒𝑥𝑡 : プロセス外部の状態
 
 定義: ある操作が外部入力であるとは、操作後の内部状態 𝑆 𝑖𝑛𝑡 ’ が、操作前の内部状態 𝑆 𝑖𝑛𝑡 と外部状態に由来
 するデータ 𝑑 ∈ 𝑆 𝑒𝑥𝑡 の関数 φ として決定されることを指す。
 𝑆 𝑖𝑛𝑡 ’ = φ(𝑆 𝑖𝑛𝑡 , 𝑑), 𝑑 ∈ 𝑆 𝑒𝑥𝑡 
 つまり、外部リソースの状態のデータによって、アプリケーションの内部状態が変更される操作 を指す。
 (例: クライアントから届くHTTPリクエスト, DB からのクエリ応答, …)
 
 定義: ある操作が外部出力であるとは、操作後の外部状態 𝑆 𝑒𝑥𝑡 ’ が、操作前の外部状態 𝑆 𝑒𝑥𝑡 と内部状態に由来
 するデータ 𝑑 ∈ 𝑆 𝑖𝑛𝑡 の関数 ψ として決定されることを指す。
 𝑆 𝑒𝑥𝑡 ’ = ψ(𝑆 𝑒𝑥𝑡 , 𝑑), 𝑑 ∈ 𝑆 𝑖𝑛𝑡 
 つまり、アプリケーションの内部状態のデータによって、外部リソースの状態が変更される操作 を指す。
 (例: 外部システムへのHTTPリクエスト, DB へのクエリ送信, …)

  8. 15 形式化の事前準備
 Primary I/O と Secondary I/O
 外部 I/O 自体は、以下のように2つに分けられる。


    
 Primary I/O:
 アプリケーション 𝐴 の処理を開始させるトリガーとなる外部 I/O。
 例) HTTP サーバーに対する HTTP リクエスト
 
 Secondary I/O:
 アプリケーション 𝐴 の実行過程において、関数 𝑓 ∈ 𝐴 が自発的に実行する外部入力および外部出力。
 例) HTTP サーバーに HTTP リクエストを飛ばした後に発生する DB クエリ
 
 いくつかのアーキテクチャでは、上記のどちらを扱うかによって、レイヤーがさらに分離される。例えば…
 • Presentation 層: Primary I/O
 • Infrastructure 層: Secondary I/O

  9. 17 テストレベルの形式化
 Unit Test
 Unit Test は、単一プロセス内 で実行され、外部 I/O が発生しない

    
 あるいは外部 I/O 発生する依存をテストダブルに置き換える テストコードである。
 
 形式化:
 テスト対象 𝑢 ∈ 𝐴 𝑜𝑤𝑛 に対するテスト 𝑡 が Unit Test であるなら、以下の条件を満たす。
 
 • プロセス閉包 
 ◦ 𝑡 および 𝑢 の実行は、単一のプロセス 𝑃 内で完結する。
 • 外部 I/O の排除
 ◦ 𝑢 に対する任意の依存 𝑣 ∈ 𝐷(𝑢) について、𝑣 が外部 I/O を伴わない。
 ◦ もしくは、外部 I/O を伴う全ての 𝑣 が、外部 I/O を伴わないテストダブル 𝑑 に置換される。
 
 この定義は、Unit Test が高速性(I/O 待機の排除)と決定性(外部状態に非依存)を保証する。
 テスト対象 𝑢 の実装サイズは小さい方がいいが、その規模に客観的基準はないので言及しない。

  10. 18 テストレベルの形式化
 Integration Test
 Integration Test は、単一プロセス内で実行 され、外部 I/O を許容する

    テストコードである
 
 形式化:
 テスト対象 𝑢 ∈ 𝐴 𝑜𝑤𝑛 に対するテスト 𝑡 が Integration Test であるなら、以下の条件を満たす。
 
 • プロセス閉包 
 ◦ 𝑡 および 𝑢 の実行は、単一のプロセス 𝑃 内で完結する。
 • 外部 I/O の許容
 ◦ 𝑢 の依存集合 𝐷(𝑢) に、テストダブルに置換されず外部 I/O を伴う関数 𝑣 ∈ 𝐴 が少なくとも1つ存在する。
 ◦ つまり、何らかの Secondary I/O が発生する。
 
 外部 I/O の許容が Unit Test との明確な境界である。
 DB へのクエリ発行やファイル操作といった、プロセス境界を越える相互作用の正当性を検証する。

  11. 19 テストレベルの形式化
 E2E Test
 E2E Test は、本番環境に近い形で検証するブラックボックステストである。
 
 形式化:
 対象システム

    𝑆 = {𝐴 1 , 𝐴 2 , …, 𝐴 𝑛 } に対するテスト 𝑡 が E2E Test であるなら、以下の条件を満たす。
 
 • プロセス分離 
 ◦ テスト 𝑡 の実行プロセス 𝑃 𝑡 は、アプリケーションのプロセス {𝑃 𝐴𝑖 } とは独立である
 • 外部からの観測 
 ◦ 𝑡 は 𝑆 に対して外部入力を与えることで {𝐴 𝑖 } を実行し、その結果生じる外部出力などを検証する。
 ◦ つまり、何らかの Primary I/O を発生させる 。
 ◦ {𝑃 𝐴𝑖 } 内部のメモリ空間 𝑀 𝐴𝑖 には直接アクセスしない。
 
 プロセスが分離され、外部I/Oを通して検証する点で、Integration Test とは明確に異なる。
 ブラウザーを介する Browser E2E だけでなく、バックエンドを外側から実行する Backend E2E も内包される。

  12. 21 アーキテクチャとの対応付け
 Domain Layer
 責務:
 • 外部 I/O を扱わない純粋な業務ロジック 


    ◦ 例) 計算・分岐・判定・状態遷移...
 ◦ 外部 I/Oが発生しないため、必ず Unit Test で済ませる
 
 依存関係:
 • 他のいかなるレイヤーにも依存しない 
 ◦ 実装サイズが小さく、それ故に Test Scope が小さくすむため、テストが容易である
 ◦ 逆に、網羅的なテストを domain で行えるように、計算・分岐・判定の詳細を集約する
 

  13. 22 アーキテクチャとの対応付け
 Infrastructure Layer
 責務:
 • (a) 外部リソースに対する読み書き 
 ◦

    すなわち、Secondary I/O の実行である (例: DBの永続化、外部サービス通信)
 ◦ Integration Test が忠実かつ必要最小限なテストである
 ◦ I/O 発生箇所をテストダブルに置き換えた Solitary Unit Test で相互作用を検証してもいい
 • (b) 上記で発生する外部入力と外部出力の変換 
 ◦ 例: Domain Model ↔ 外部入出力
 ◦ 変換ロジックをクラスや関数として切り出し、Unit Test で検証すればよい。
 
 依存関係:
 • domain 層のみに依存する 
 ◦ 比較的依存が少ないため、テストの実装コスト自体は小さい
 ◦ とはいえ外部 I/O が発生するので、上記以外の詳細なロジックを持つべきでない
 

  14. 23 アーキテクチャとの対応付け
 Presentation Layer
 責務:
 • (a) Primary I/O のハンドリング

    
 ◦ 忠実にテストしようとすると Primary I/O を再現できる E2E Test 以外に選択肢はない
 • (b) 外部入力の薄い検証 (Sanity Check)
 ◦ 検証ロジックを Validator などに分離して Unit Test を書けばよい
 • (c) usecase への委譲
 ◦ ほとんど機能全体の検証に近く、Unit Test は適さない 
 ◦ infrastracture に依存して Secondary I/O が発生する
 ◦ E2E Test でついでにハッピーパスを検証 するか、usecase の Integration Test に委譲する
 
 依存関係:
 • 他のいかなるレイヤーにも依存できる 
 ◦ 依存が多く、Secondary I/O も発生するため、責務 (b) 以外では Unit Test の費用対効果が低い 
 ◦ なるべくハッピーパスのテストで済むように、詳細なロジックを持つべきではない

  15. 24 アーキテクチャとの対応付け
 Usecase Layer
 責務: 
 • (a) コーディネーションロジック 


    ◦ domain と infrastructure の部品を “協調” させ、ユースケースを達成する
 ◦ ほとんど機能全体の検証に近く、Unit Test は適さない 
 ◦ infrastracture に依存して Secondary I/O が発生する
 ◦ E2E Test でついでにハッピーパスを検証 するか、Integration Test で検証する
 • (b) トランザクション境界の管理 
 ◦ DB を扱った Integration Test で検証する
 ◦ E2E Test でも検証してもよいが、そのためにしてはエッジケースであると捉えられる
 
 依存関係:
 • domain + (domain の interface) を通して infrastructure に依存
 ◦ presentation層と同様の理由で、Unit Test の費用対効果が極めて低い 
 ◦ 逆に、Unit Test が必要になるような詳細なロジックの実装は避けるべき

  16. 25 アーキテクチャとの対応付け
 アーキテクチャマトリクス 
 
 App Layer
 Responsibility
 Test Scope


    Suitable Test
 Domain
 Business Rule
 Small
 Unit
 Business Service Logic
 Small - Medium
 Integration
 Usecase
 Coordination
 Medium - Large
 Integration, E2E
 Transaction
 Medium
 Integration
 Infrastracture
 Secondary I/O
 Small - Medium
 Integration
 Conversion
 Small
 Unit
 Presentation
 Primary I/O
 Medium - Large
 E2E
 Coordination (Exec Usecase)
 Medium - Large
 Integration, E2E
 Conversion
 Small
 Unit
 適用事例の中には、Infra + Presenter = Adapter レイヤーとする例もあったが、責務に分解することで同様 に応用が可能だった。
  17. 27 ケーススタディ
 以下のステップで提案手法を適用。
 
 1. リグレッションテストスイートを定義
 a. 手法の適用に集中するために、問題空間を固定する
 2. テストケースごと、テスト目的と関連づけられるアプリケーションレイヤーの責務を特定


    a. テスト目的が複数のアプリケーションレイヤーの責務と関連づく場合は、テストケースの分割を行う
 3. “アーキテクチャとテストレベルの対応付け”に従って、適切なテストレベルを特定 
 4. テストレベルごと、テストケースの目的と形式的定義を満たす自動テストを実装
 適用手順

  18. 28 ケーススタディ
 先行研究である「Enhancing SaaS Product Reliability and Release Velocity through

    Optimized Testing Approach」で提案した重篤度に基づくテストケース選定 を実施。
 
 これにより、デグレによる障害を防ぐためのリグレッション テストスイートを作成。
 フィーチャーに対して リスク分析 ⾼リスク? 論理的機能構造アイテム を重篤度で分類 重篤度: ⾼? テストケースをリグレッ ションテストスイートに 含める Yes Yes 論理的機能構造アイテム ≒ テストケース リグレッションテストスイートの定義 

  19. 31 評価と考察
 以下の観点から、提案手法の有用性を評価する。
 
 1. テスト構成の最適化
 a. 形式的なテストレベル定義とArchitectural Mappingは、実際の大規模システムにおいてテスト構成の 偏りを是正できるか?


    2. 効率性の改善
 a. 提案手法は、手動テスト工数の削減、デプロイ頻度の向上を実現できるか?
 3. 品質の維持
 a. テスト構成の最適化は、本番環境の品質を維持できるか?
 4. 実用性
 a. 提案手法は、実際の開発現場で受け入れられ、継続的に運用可能か?
 評価の方法 

  20. 32 評価と考察
 手法適用前は手動によるテスト実行がほとんどで一部を自動E2Eテストで実施していたが、手法 適用後は、多くをUnit TestやIntegration Testでまかなえるようになった。
 テストレベル間の比率も概ねテストピラミッドに沿っており、テスト構成のバランスが良い状態を 実現したと言える。
 テスト構成を最適化するか 


    テストレベル テストケース数 比率 Unit Test 78 66% Integration Test 28 23% E2E Test 10 9% 手動テスト 2 2% ※テストケース数はテスト関数の 数を指しており、テストケースごと に複数のテストパターンが実装さ れている。
 概ねテスト目的の単位でテスト関 数が分割されているため、今回は テスト関数の数で構成比を考え た。

  21. 36 評価と考察
 • テストスイートの最適化
 ◦ 「E2E Testが存在する場合はpresentation層の”usecase への委譲”に対する Integration Testは不要」といったテストケース間の重複を踏まえたテストスイートの最適

    化(テスト間の重複削除)は、個別判断の余地が残っている。
 
 ◦ →今後の展望として、テストのカバレッジと包括関係に基づいた「冗長性判定の手法確立」 に取り組みたい。
 実用性の課題 

  22. 37 評価と考察
 • リファクタリングの必要性
 ◦ 一部の自動テスト実装を行う前に、DI(依存性注入)の改善や不適切な依存の修正をする 必要があった。
 ▪ また、このリファクタリングの必要性は様々なMicroserviceにおいて生じた。
 ◦

    上記の発見から、提案手法の現実的な適用のためには自動テスト実装の前に「テスタビリ ティを確保するための実装、あるいは実装レビュー」というプロセスが必須であることが分 かった。
 
 • 形式化の適用範囲
 ◦ ほとんどのテストは提案手法の形式化に当てはめることができたが、開発体制によっては 重要度が高まるContract TestingやEKS cluster上のpod間疎通確認などは形式化の対 象外になっている
 適用時の課題