Closed11

バグの発生原因パターンを整理して、しんどくないテスト実装を考える

ハトすけハトすけ

テスト分類

よくテストは次のような分類がされる

テストの分類

テスト粒度

  • ユニットテスト(単体テスト): モジュールやコンポーネントといった小さな単位でテストを行います。個々の機能が正しく動作することを確認します。
  • 統合テスト: 複数のモジュールを組み合わせてテストを行います。モジュール間のインターフェースやデータのやり取りが正しく行われるかを確認します。
  • E2Eテスト (End-to-Endテスト): システム全体を、ユーザーが利用する環境に近い状態でテストします。実際のユーザーシナリオに基づいて、システム全体の動作を検証します。

テストの種類

  • 機能テスト: システムが仕様通りの機能を満たしているかを検証します。
  • パフォーマンステスト: システムの応答速度、処理能力、安定性などを測定します。
    • 負荷テスト: 高負荷状態でのシステムの挙動を検証します。
    • ストレステスト: システムの限界性能を測定します。
  • セキュリティテスト: システムの脆弱性を検出し、セキュリティリスクを評価します。
    • 脆弱性スキャン: 既知の脆弱性がないかを自動的に検査します。
    • 侵入テスト: 攻撃者の視点でシステムに侵入を試み、脆弱性を発見します。
  • ユーザビリティテスト: システムの使いやすさ、分かりやすさを評価します。
  • 互換性テスト: 異なるOS、ブラウザ、デバイスなどでシステムが正しく動作するかを検証します。

プログラム化するかどうか

  • 自動テスト: テストケースをプログラムで記述し、自動的に実行します。
    • 回帰テスト: 修正や変更によって既存の機能に影響がないことを確認するためのテスト。自動化に適しています。
  • 手動テスト: テスターが手動で操作を行い、システムを検証します。
    • 探索的テスト: テスターの経験や知識に基づいて、テストケースをその場で考えながらテストを行います。
    • モンキーテスト: ランダムな操作を行い、システムの予期せぬ動作やバグを発見します。

テストケースの書き方

  • given-when-then: BDDで用いられる記法。
  • describe-it: Mochaなどのテストフレームワークで用いられる記法。
  • JUnit: Javaのテストフレームワーク。
  • キーワード駆動テスト: Robot Frameworkなどで用いられる記法。

開発工程における分類

  • 単体テスト: プログラミングと並行して行われることが多い。
  • 結合テスト: 単体テストが完了したモジュールを組み合わせて行う。
  • システムテスト: 開発工程の終盤に、システム全体を対象に行う。
  • 受け入れテスト: 顧客がシステムを受け入れるかを確認するためのテスト。

モジュールにおけるテスト対象の範囲

  • ブラックボックステスト: システムの内部構造を考慮せず、入力と出力の関係に基づいてテストを行います。
  • ホワイトボックステスト: システムの内部構造を考慮し、コードのロジックを検証します。

テスト手法

  • 境界値分析: 入力値の境界値付近を重点的にテストします。
  • 同値分割: 入力値を同値クラスに分け、代表値を選んでテストします。
  • デシジョンテーブルテスト: 条件と結果の組み合わせをテーブルで表し、網羅的にテストします。
  • 状態遷移テスト: システムの状態遷移図に基づいて、状態遷移を網羅的にテストします。

その他

  • 静的テスト: コードを実行せずに、コードのレビューや静的解析ツールを用いてバグを発見します。
  • 動的テスト: コードを実行して、システムの動作を検証します。

これらの分類を組み合わせて、プロジェクトやシステムの特性に合わせたテスト戦略を立てることが重要です。

ハトすけハトすけ

テストと品質2

品質といえばソフトウェア品質(JIS X 25010:2013)が有名
https://zenn.dev/dove/articles/ed0046f46ad9f4

これを覚えるのが大変な人はとりあえず「わかる、できる、素早くできる」だけでも覚える
3大テスト品質

これらの品質を下げないためにそれぞれテストが対応する

品質項目 テスト対応項目 大雑把な把握
機能適合性 機能テスト できる
性能効率性 パフォーマンステスト 素早くできる
互換性・移植性 互換テスト
使用性 ユーザビリティテスト わかる
信頼性 カオステスト
セキュリティ セキュリティテスト
保守性 静的解析ツールで担保
ハトすけハトすけ

なぜ品質が落ちるのか

テストが品質を落とさないためのものだとわかった。ではなぜ品質が落ちるのか。
先程の品質の分類で品質が高い場合と低い場合を比較する

品質項目 高い 低い
機能適合性 期待した結果を得られる 期待した結果を得られない
性能効率性 期待した結果を素早く低いコストで得られる 期待した結果を得られるがコストがかかる
互換性・移植性 他の場所でも使える 他の場所で使えない
使用性 わかりやすい わかりにくい
信頼性 頑丈 壊れやすい
セキュリティ 安心して使える 損害を受ける可能性がある
保守性 修理しやすい 修理しにくい

優先順位(多分人によって変わるが)

  1. 期待した結果を得られる
  2. 安心して使える
  3. 期待した結果を素早く低いコストで得られる
  4. わかりやすい
  5. 頑丈
  6. 修理しやすい
  7. 他の場所でも使える

ここではソフトウェアにおいて互換性はほぼ機能適合性だと思われる。APIのバージョンが少し上がったら使えなくなるのは、ほぼありえないと考えられる。
SaaSにおいて修理しやすいのはユーザーの関心事ではない。

なぜ品質が落ちるのか

  • 機能にバグがあり使えない
  • 実行時間が極端に遅い
  • わかりにくい
  • アップデートがあるたびになにか壊れている
  • 情報漏洩インシデントが発生しやすい
  • 特定の限られた状況でしか利用できない(想定ユースケースをカバーできていない)
ハトすけハトすけ

なぜ機能にバグが発生するのか

機能を 入力 -> (処理) -> 出力 と一般化すると、バグの発生要因はロジックかスキーマの大きく2つ。さらにロジックにも関連するが設定値で振る舞いを変える機能の場合設定値の不備も挙げられる

  • ロジックの不備
    • そもそも機能が難しい
      • 競合状態が発生しやすいアルゴリズム
    • (自動・手動)テストケースが異常時のシナリオをカバーしきれていない
  • スキーマの不備
    • モジュール間のインターフェースが異なってしまった
      • アップデート時のAPIとフロントエンドの要求するAPIの形が違う
  • 設定値の不備
    • 環境差分(本番環境と開発環境に差がある)
    • 環境変数、外部サービスの設定を反映し忘れ
    • タイムゾーンなどの設定が不適切だった(知識不足などにより)
ハトすけハトすけ

なぜ実行時間が極端に遅いのか

  • 実行時間が遅いアルゴリズムを採用しているから
  • 配布コンテンツの容量がでかい
  • ユーザーの環境スペックが足りていない(インターネットの回線が遅いなど)
  • サービスのサーバースペックが足りていない、スワップが発生している
  • 実際にそのアーキテクチャ・アルゴリズムで想定時間内に収まるのかを観測していない
    • 想定データ量を見積もりできていない
    • パフォーマンステストを実施していない
    • リクエストの平均レスポンス時間などを観測していない
ハトすけハトすけ

なぜわかりにくいのか

  • ユーザーの声をきいていないから
  • ビジネスの要求を愚直に体現したUIになっており、複雑すぎる
  • できることが多すぎる
  • 開発者側のデザインスキルのレベルが低い
  • ユーザーの想定レベルを見誤っている
ハトすけハトすけ

なぜアップデートがあるたびになにか壊れているのか(リグレッション)

  • 回帰テストを書いてないから
  • 回帰テストのカバー率が低いから
  • システムの根本的な概念モデルが間違っているから
    • 無理やりユースケースと結びつけようとしていびつになっている
  • 壊れやすい書き方をしているから、技術を使っているから
    • グローバル状態を多用するなど
    • スレッドプログラミング
ハトすけハトすけ

なぜ情報漏洩するのか

いまセキュリティインシデントが発生している主な侵入経路は2つ

  • OSSに悪意のあるコードを含み、それを取り入れたサービスに攻撃をする
  • その企業に属するユーザーにフィッシングメールなどを送り、悪意のあるアプリをPCにインストールさせる

システム自体に防御を施すと同時に、組織の人間を教育する必要がある。

ハトすけハトすけ

なぜ想定ユースケースをカバーできないのか

  • ユーザーから学んでいないから
  • 学んだものをシステムに還元してないから
    • 開発体制が継続的改善サイクルにマッチしていない
    • 開発環境を整備できていない
ハトすけハトすけ

対策

  • ロジックのバグ
    • そもそもテストを書く(テストカバレッジの最低目標)
    • 境界値、異常値のテストを充実させる
    • 競合状態が発生しやすい部分は頑張る
  • スキーマのバグ
    • 統合テストを行う
    • スキーマのバージョン管理を行う
    • 互換性のある開発を行う
    • 重要なシナリオはE2Eテストを実施する
  • 設定値のバグ
    • TerraformなどInfra as a Codeを採用する
    • Build Once, Deploy Manyなコンテナ戦略で環境差分をなくす
  • リグレッションを発生させない
    • 自動テストをCI/CDパイプラインに導入する
    • 回帰テストを充実させる
  • 実行時間が遅い
    • アルゴリズムを意識する
    • パフォーマンステストを実施する
    • リクエストの平均レスポンス時間を観測しアラートを作成する
  • 情報漏洩対策
    • コンテナの脆弱性スキャンを活用する
    • あればコンテナ内部を変更しない設定を有効にする
    • OSSを利用するときは中身をちゃんと把握する
  • UX改善
    • できる限りユーザーの生の声、生の操作を観測する
    • UXを意識する
このスクラップは2025/01/17にクローズされました