goo blog サービス終了のお知らせ 

ウィリアムのいたずらの、まちあるき、たべあるき

ウィリアムのいたずらが、街歩き、食べ物、音楽等の個人的見解を主に書くブログです(たま~にコンピューター関係も)

ユニットテストの基本を聞いてきた!(単体テストの作り方と、ミューテーションテストも追加)

2025-06-07 10:58:43 | JavaとWeb
今(6/7)、JJUG CCC に行っていて、
さっきまで「ユニットテスト基礎講座」を聞いてきたので、
その内容をメモメモ

P.S 16:25ごろ追加
 その後のセッション
・単体テストの始め方/作り方
・Mutation Testingのプロジェクト実践
も追加してシェア!



■ユニットテスト基礎講座

アーキテクトの教科書という本を書いている人
Xのアカウントから資料見れる
テスティングフレームワークに触れた人対象
考え方中心

内容
・ユニットテストの基本概念
・テスト対象
・質の良いテスト



●ユニットテスト、書いてますか
 8割くらい
 ユニットテストを十分にかけていますか
 ユニットテストを上手にかけていますか

 ユニットテストを書くのは当たり前
 書籍など情報源は少ない
 ベストプラクティスが浸透していない

●テストコードはAIにかかせればよくね?
 事実AIにテストコードは書かせる
  →任せっぱなしはよくない

 理由①:AIが生成するテストは平均点(かそれに満たない)
 理由②:AIは間違える(うそもつく)
 テストコードはvibe cordingするべからず
 雰囲気でやるのはX
 AutomatedTestの知識



●Part1:ユニットテストの基本概念
 ユニットテストとは
 テストのピラミッド
  E2Eテスト
  インテグレーションテスト
  ユニットテスト

 ユニットテストと統合テストの境界はあいまい(解釈による)
 Googleでは、共通理解促進のため、テストサイズ(S/M/L)による分類

 ユニットテスト
 単体と呼ばれる少量のコードを検証すること
 実行時間が短い
 隔離された状態で実行

 古典学派とロンドン学派異なる(テスト駆動開発の本に書いてある)
 →古典学派にのっとる
 1単位のふるまいを検証
 他のテストケースから隔離

 ユニットテストの目的
  期待通りに正しく動作することを検証する
  退行を防ぐ
  テストコードという実例を通して理解しやすくする

 たんにテストを作成すれば十分ではない→テストの質
 テストコードは散らかりやすい(プロダクションコードの数倍)
 テストコードのSOS
  構造化
  整理
  自己文書化
   →頭文字でSOS



●Part2 テスト対象のふるまい

・1単位のふるまいを識別する
 ユニットテストを書かせる:ちゃんと書いている。カバレッジ97

・テストの網羅性は十分か?
 振る舞いが大きすぎる
 →トランザクションスクリプトはユニットテストに不向き
  →分割して統治せよ
   小さな振る舞いに分割する

 処理フローロジックと中核ロジックに分かれる

 関心の分離
  因子数が少なくなる
   因子水準
    パラメータ:因子
    パラメータがとる値:水準

 組み合わせテスト
  全網羅→爆発
  間引き方
   2因子網羅→直行表・ペアワイズ
  
まとめ
 1単位のふるまいを識別
 分割して統治
 テストしやすくなる



●Part3 よいテストコードを書くには
 S構造化されている
  →パッケージ構造
   垂直構造(業務観点)でパッケージを設計すべき
   Cf水平分割(技術観点)

  テストケースの階層化
   内部クラスを用いてテストケースをグループ分けする
  階層化のメリット
   テストランナーで視覚的に構造を俯瞰できる、ドリルダウンできる

  O:整備されている
   グループ分け
    正常系
    準正常系
    異常系
   テスト設計の根拠はわからない:別途のこしておく
    →JavaDocコメント

   パラメータ化テスト
    パラメータを外だし(アノテーションつける)

  S:自己文書化されている
   一目見ただけで、わかる
    テストの名称:テスト条件と期待する振る舞いがわかる
    AAAまたはGiven-When-Then
     AAA:Arrange準備、Act実行、Assert検証にわけて記述
   可読性を考慮する
   実用的なコードだと、ArrangeとAssertは記述長くなりがち
    SUT:テスト対象の構成要素
    Doc:SUTがいジョンするもの
    テストフィクスチャー:テスト実行に必要なものすべて

 大きな振る舞いに対するユニットテスト
  小さく分割した振る舞いをテストした後は
  →処理フローロジックのテストは必要か?
  単独でテストするのではなく、集合体でテスト(コンポーネント)
  集合体として提供する振る舞いをテストする
   代表パターンとエッジケースでいいときも

 テストダブルの使い方
  テスト:ダブル実際のコンポーネントの代替
   スタブとモック

 間接入力
  SUTはDoCとの相互作用により、振る舞いを実現
  DoCが返す結果=SUTにとっての間接入力
  スタブを使う
    制御困難
    複雑なオブジェクトグラフ
    通常だと発生しない例外
    期待する間接入力

  間接出力
   副作用として発生するもの
   間接出力の観測:モックを使う
   →つかわずにすまないか考える(副作用がなくなるように)

 テストダブルまとめ
  使わないで済むか
  スタブ:適切に
  モック:つかわないですむか

 テストパターン
  テスト特有のパターン

 小まとめ
  SOSの整理
  小さな振る舞いを網羅してから大きな振る舞いへ



●キーメッセージ
1.ユニットテストの意義
  1単位のふるまい
  振る舞いの識別と分割:設計と表裏一体

2.テスト容易性
  小さく分けるテスト設計しやすい

3.テストコードを重要な資産として扱う
  テストコードのSOS



●しつもん
・パッケージソフトのユニットテスト、どこから手を付けたら
 レガシーシステム全般に言える
 全部テストしたらとんでもない工数
  重要な所
  変更頻度が高いところ
   →テストコードが書けないか、
 重要なテストケース



■単体テストの始め方/作り方
(リスペクトです。パクリではないです)

・今回の例:予約注文処理を加えるとき
  通常の商品は在庫確認(既存仕様)
  予約注文の商品は在庫を確認しないで注文

・まずはテストをかこう
 パターンに沿って書く
  テスト駆動開発
 コードを書く前に失敗する自動テストコードを必ず書く
 重複を除去する

・まずは日本語でテストケースを書いてみよう
 予約商品を注文すると予約される

 AAAパターン
 3つのプログラムに分ける
 ・Arrenge(準備):注文商品が予約商品
    ③ActとAssertを満たすように
 ・Act(実行):注文をする
    ①もっとも簡単なActから書く
 ・Assert(確認):予約注文として登録されるか
    ②検証したいことを確認

 テストコードと日本語のコメントが1;1で対応する

・テストのふるまいは入力と出力が決める
  入力:引数
     隠れた入力:時刻、状態、外部プロセス(DBなど)
  出力:戻り値
     隠れた出力:状態、外部プロセス

・隠れた入力と隠れた出力をテストするには
 1.公開する
   状態を返す
   戻り値として

 2.テストダブルを使う
   DI

・リファクタリングしてできた

・テストはDryよりDAMP:テストはより説明的に
 Googleのソフトウェアエンジニアリング

・わかりやすい検証を選ぶ

・まとめ
 まずはテストコードから
 AAAパターンを日本語で考えよう
 入力と出力・隠れた入力と隠れた出力を分けて考えよう
 わかりやすいテストコードを加工
 DRYよりDAMP
 わかりやすい検証を選ぶ



■Mutation Testingのプロジェクト実践

・自己紹介

・問題意識の共有
 テストコードを書けば品質が良い?
  すべてのふるまいを検証できている?見切れない
 カバレッジを通せば品質が良いか?
  コードカバレッジでは測れないところ

・MutationTestingとは
 (ミューテーションテスト)

 ソースコードに意図的なバグ(=ミュータント)を入れる
 そのバグを検出できるか
   バグ検出できる(Killed(成功)

 PIT(PITest)とは
 Java向けミューテーションテストツール
  バイトコードを操作して、小さな変異(ミュータント)を自動で埋め込む
  コードを書き換えても、テストが成功する:テストが弱い

・プロジェクト実践
 Spring Boot+MyBatisのレイヤードアーキテクチャ
 PITが埋め込む
  テストは@SpringBootTestで
  PITとの併用可能→遅くなる
  →対応:ナイトりービルド、PITのインクリメンタルモード

 インフラ層は使えない
 DBUにtなどほかのツール併用

 CI/CDパイプラインとの統合
 GitHub ActionやJenkinsと統合可能だが、プッシュ、プルリク実行するのは非現実的
  →スケジュール実行(ナイトビルドなど)

 生成AIが作ったテストコード
  生成されたテストコードの多くがHappyPath(正常系で記載)
  ミュータントが残る→人間が補強、ミューテーションレポートを読みながら…
  数日後には変わっているかも

・質問
 認証回りのテストは?
 セットアップが多いことはある→分離する
  ログインとその先でわける

この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ふたば製麺は海老、となりの... | トップ | 高橋源一郎の飛ぶ教室で言っ... »
最新の画像もっと見る

JavaとWeb」カテゴリの最新記事