コンテンツにスキップ

システムテスト@ブラックボックステスト

01. システムテスト (総合テスト)

システムテストとは

『総合テスト』ともいう。

既存機能/追加/変更を含む全てのコンポーネントを組み合わせ、全てのコンポーネント間の連携が正しく動作しているかを検証する。

testing_blackbox-test_unit_integration_system


システムテストの種類

▼ 機能テスト

システムが機能的な品質を満たしているかを検証する。

テストの種類 検証内容
正常系 (成功で終わる操作) 操作の種類 (登録、参照、更新、削除) 、画面遷移、ステートマシン、セキュリティなど
異常系 (エラーで終わる操作) 操作の種類 (登録、参照、更新、削除) など
組み合わせ 同時操作、割り込み操作、排他制御に関わる操作など
業務シナリオ シナリオに沿ったユーザーによる一連の操作
開発者シナリオ シナリオに沿った開発者による一連の操作 (例:手動コマンドなど)
外部ソフトウェア連携 外部のAPIとの連携処理に関わる操作

▼ 非機能テスト

システムが非機能的な品質を満たしているかを検証する。

テストの種類 各非機能的な品質との対応関係
ストレステスト 耐久性
ロードテスト 耐久性
可用性テスト 可用性
耐障害性テスト 耐障害性
Testing in production 耐久性
ペネトレーションテスト 安全性


テスト結果の可視化

▼ テストレポート

ツールによっては、テスト結果からテストレポートを作成してくれる。

▼ バグ管理図

プロジェクトの時、残存テスト数と不良摘出数 (バグ発見数) を縦軸にとり、時間を横軸にとることにより、バグ管理図を作成する。

それぞれの曲線の状態から、プロジェクトの進捗状況を読み取られる。

品質管理図

不良摘出実績線 (信頼度成長曲線) は、プログラムの品質の状態を表し、S字型でないものはプログラムの品質が良くないことを表す。

信頼度成長曲線の悪い例


02. 機能テスト

機能テストとは

機能的な品質を満たせているかを検証する。

ホワイトボックスでの機能テストとは意味合いが異なるので注意する。

テストケース

ユーザー操作の前提や検証内容をまとめたドキュメントのこと。

前提条件 操作の種類 検証方法 期待値 OK/NG
... 参照 ... ... ...
... 作成 ... ... ...
... 更新 ... ... ...
... 削除 ... ... ...


03. 性能テスト

性能テストとは

performance-test

一定時間内に、ユーザーが一連のリクエスト (例:ログイン、参照、登録、ログアウト) を行った時に、あらかじめ定めた指標にどのような変化があるかを検証する。

具体的にはテスト時に、アクセス数を段階的に増加させて、テストレポートとしてグラフ化する。

テストレポートを元に、想定されるリクエスト数が現在の性能にどの程度の負荷をかけるのかを確認し、加えて最大負荷の場合でも性能目標を満たしているかを確認する。

これらを運用時の監視の参考値にする。


性能テストの種類

  • ストレステスト
  • ロードテスト
  • 耐久テスト
  • スパイクテスト
  • 拡張性テスト


性能指標

  • 平均スループット
  • 平均レスポンスタイム
  • 平均ハードウェア使用率
  • 時間当たり平均トランザクション数 (TPS:Transaction Per Second)


機能別の性能目標値

KPI (組織内の合意) に基づいて、各機能ごとに性能指標の目標値を決める。

SLA (顧客との合意) に基づいたSLOとは区別したい。

例えば、1秒間に50人のユーザーからリクエスト (50個/秒のリクエスト) があり、この時のとある機能でレスポンスタイム目標値は3秒以内であるとする。

この場合、平均スループットの目標値は50 (個/秒) 、平均レスポンスタイムの目標値は3秒以内、となる。

項目 平均スループット目標値 (件/秒以上) 平均レスポンス目標値 (秒以内) ハードウェア使用率目標値 (最大率)
機能A 50 3 60%
機能B ... ... ...
機能C ... ... ...


ユースケース

オートスケーリングがある場合とない場合で、ネットワークの性能指標 (スループット、レスポンスタイムなど) にどの程度の違いがあるかを確認する。


03-02. ロードテスト (負荷テスト)

ロードテストとは

実地を再現した (許容の限界値を含む) 負荷をシステムに与えた時に、どのように動作するかを確認する。

許容以上の負荷を与えるストレステストとは区別すること。


ユースケース

▼ 例

実地的な負荷状況で、オートスケーリングが品質を満たしているか (有効に機能するか) を確認する。

▼ 例

性能の限界値に達するほどのリクエスト数が送信された時に、障害回避処理 (例:アクセスが込み合っている旨のページを表示) が実行されるかを検証する。

具体的にはテスト時に、障害回避処理以外の動作 (エラー、間違った処理、障害復旧後にも復旧できない、システムダウン) が起こらないか否かを確認する。


設計規約

▼ ロードテストツール

  • Jenkins
  • Grafana k6 (JavaScriptでシナリオ定義できる)
  • Gatling (Scalaでシナリオ定義できる)
  • Taurus (他のロードテストツールのラッパー)

▼ 事前作業

  • ロードテスト前にアラートを無効化して
  • 実行環境を占有させてもらうことになるため、関係者と実施日を調整する。

▼ シナリオの種類

  • 一定数のリクエストを送信し続ける。
  • 送信するリクエスト数を増加 (直線的、指数関数的など) させていく。
  • 最初は一定数のリクエストを送信し、途中からリクエスト数を増加させていく。

▼ テストレポートによる評価

  • %を判断基準に使用する。レスポンスの95%が、ネットワークの性能指標 (スループット、レスポンスタイムなど) で一定水準以下の値であることを確認する。


ロードテストのテストケース

▼ 背景

アプリで、開始からピークまでに次のようにリクエスト数が増し、障害が発生した。

今回、障害に耐えられるようにスペックを向上させた。

障害時のデータに基づいてロードテストを実施し、障害時と同じ負荷に十分耐えられるかどうかを検証する。

障害発生期間 合計閲覧ページ数
(PV数/min)
平均ユーザー数
(UA数/min)
ユーザー当たり閲覧ページ数
(PV数/UA数)
13:00 ~
13:05 (開始)
300 100 3
13:05 ~
13:10
600 200 3
13:10 ~
13:15 (ピーク)
900 300 3
ランキング URL 割合
1 /aaa/bbb/* 40%
2 /ccc/ddd/* 30%
3 /eee/fff/* 20%
4 /ggg/hhh/* 10%

▼ テストケース

ユーザー当たりの閲覧ページ数はループ数に置き換わるため、ループ数は『3回』になる。

障害発生期間の閲覧ページ数はスレッド数に置き換わるため、スレッド数は『1800個 (300 + 600 + 900) 』になる。

障害発生期間は、ランプアップに置き換わるため、ランプアップ期間は『900秒 (15分間) 』になる。

スレッド数 (個) ループ数 (回) ランプアップ期間 (秒)
1800 3 900


03-03. ストレステスト (限界テスト)

ストレステスト

許容以上の負荷をシステムに与えた時に、どのように動作するかを確認する。

また、テストレポートから、運用時の監視で参考にするための、安全範囲 (青信号) 、危険範囲 (黄色信号) 、限界値 (赤信号) 、を導く必要がある。

実地を再現した (許容の限界値を含む) 負荷を与えるロードテストとは区別すること。


設計規約

▼ ストレステストツール

  • Jenkins
  • Grafana k6 (JavaScriptでシナリオ定義できる)
  • Gatling (Scalaでシナリオ定義できる)
  • Taurus (他のロードテストツールのラッパー)

▼ 事前作業

  • ストレステスト前にアラートを無効化しておく。
  • 実行環境を占有させてもらうことになるため、関係者と実施日を調整する。

▼ シナリオの種類

  • 一定数のリクエストを送信し続ける。
  • 送信するリクエスト数を増加 (直線的、指数関数的など) させていく。
  • 最初は一定数のリクエストを送信し、途中からリクエスト数を増加させていく。

▼ テストレポートによる評価

  • %を判断基準に使用する。レスポンスの95%が、ネットワークの性能指標 (スループット、レスポンスタイムなど) で一定水準以下の値であることを確認する。


03-03. 耐久テスト

耐久テストとは

長時間の大量リクエストが送信された時に、短時間では検出できないどのような問題が存在するかを検証する。

具体的にはテスト時に、長時間の大量リクエストを処理させ、問題 (例:微量のメモリリークが蓄積してメモリを圧迫、セッションデータが蓄積してメモリやストレージを圧迫、ログが蓄積してストレージを圧迫、ヒープやトランザクションログがCPUやI/O処理を圧迫) を発生させる。

これにより、どんな問題が起こるか否かを確認する。


04. 可用性テスト

可用性テストとは

システムで意図的に障害を起こし、その時に可用性の仕組みが正しく発動し、非機能的な品質を満たしているかを検証する。


目標値の指標

▼ RPO (目標復旧時点)

障害が発生した時に、どの時点まで遡ってデータを復旧させるかの目標値のこと。

もしRPOが5分間だとすると、5分間のデータ欠損は復旧できず、これを許容することになる。

▼ RTO (目標復旧時間)

障害が発生した時に、障害後どの時間以内にデータを復旧させるかの目標値のこと。

言い換えると、ダウンタイムの最大許容時間である。

もしRTOが1時間だとすると、1時間は障害が起こったまま (ダウンタイム) になり、これを許容することになる。


可用性テストのテストケース

▼ 背景

今回、KubernetesのNode上で、Kubernetesリソースとアプリが稼働するシステムを開発した。

可用性テストを実施し、障害が起こっても利用可能な時間を確保できるかどうかを検証する。

項目 技術
仮想サーバー AWS EC2 (オートスケーリングあり)
アプリ Go
リバースプロキシ Nginx
コンテナオーケストレーション Kubernetes
サービスメッシュ Istio
メトリクスの収集 Prometheus
ログの収集 Fluentd
分散トレースの収集 Jaeger
テレメトリーの監視 Prometheus
サービスメッシュの可視化 Kiali

▼ テストケース

各テストケースで、カオスエンジニアリングやフォールトインジェクションを実施する。

障害発生時にシステムが高い可用性を発揮できるかを確認する。

障害名 フォールトインジェクション 検証方法 検証方法のコマンド 期待動作
Nodeの停止障害 AWS EC2を停止させる。 Node内でroot権限でカーネルパニックを意図的に起こし、その状態でもシステム全体として稼働し続けられるか否かを確認する。 aws ec2 stop-instances --instance-ids <インスタンスID>
echo 1 > /proc/sys/kernel/sysrq && echo c > /proc/sysrq-trigger
・冗長化された稼働中のNode上で、レプリカ数を維持できるだけのPodが起動する。
・オートスケーリングによって、停止したNodeに代わり新しいNodeが起動する。
・Nodeのヘルスチェックが正常である。
Podの停止障害 GoのPodを停止させる。 kubectlコマンドでPodを強制的に終了し、その状態でもシステム全体として稼働し続けられるか否かを確認する。 kubectl delete pod <Pod名> --grace-period=0 --force ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・アプリが正しく動作している。
NginxのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・アプリが正しく動作している。
kube-state-metricsのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・データを全て収集できている。
PrometheusのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・データを全て収集できている。
FluentdのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・ログを正しくルーティングできている。
GrafanaのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・ダッシュボードにログインできる。
・データを正しく可視化できている。
AlertmanagerのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・ダッシュボードにログインできる。
・アラートを正しくルーティングできている。
KialiのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・ダッシュボードにログインできる。
・アラートを正しくルーティングできている。
JaegerのPodを停止させる。 同上 同上 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・ダッシュボードにログインできる。
・アラートを正しくルーティングできている。
Istioでフォールトインジェクションを実施する。 Istioの機能を使用する。 可用性テストの時だけ、マニフェストにフォールトインジェクションの設定を追加する。 ・オートスケーリングによって、停止したPodに代わり新しいPodが起動する。
・ダッシュボードにログインできる。
・アラートを正しくルーティングできている。


05. 耐障害性テスト

Fault tolerance (耐障害性)

耐障害性テストとは

システムで意図的に障害を起こし、その時の耐障害性が非機能的な品質を満たしているかを検証する。


06. Testing in production

Testing in productionとは

本番環境にて実際のユーザーの手を借り、非機能的な品質を実地的に検証する (例:該当のエラーメトリクスが基準値を満たすか) 。

  • カナリアリリース中のテスト
  • カオスエンジニアリング


カオスエンジニアリング

▼ カオスエンジニアリングとは

実験的に、本番環境のマイクロサービスアーキテクチャなシステムにランダムな『カオス』を意図的に注入し、高負荷な状態に至らせる。

そのテストレポートから、システムに潜む想定外の問題を表面化させる。

カオスエンジニアリングは、実地的なテストであり (例:該当のエラーメトリクスが基準値を満たすか) 、今まさに実際のユーザーが使用しているソフトウェアに対して実施することになるため、ビジネスサイドの理解が必要になる。

ただし、必ずしても本番環境でしか使用できないわけではなく、テスト環境で実施し、起こりうる障害を洗い出すように使用しても良い。

対象となるシステムは、マイクロサービスアーキテクチャであっても、モノリシックアーキテクチャであっても、問題ない。

本格的なカオスエンジニアリングを採用している日系企業は少なく、国内事例はまだ少ない。

障害の発生対象に合わせて、ツールを選ぶ必要がある。

ツール 発生先
Chaos Mesh AWS、Google Cloud、Kubernetes
Chaos Monkey AWS

▼ フォールトインジェクション

カオスエンジニアリングの一種である。

マイクロサービスアーキテクチャなシステムの一部分にランダムな障害を意図的に注入し、高負荷な状態に至らせる。

障害の発生対象に合わせて、ツールを選ぶ必要がある。

ツール 発生先
Istio Kubernetes
AWS Fault Injection Simulator AWS

▼ 手順

(1)

本番環境のシステムから様々なテレメトリーを収集し、安定している通常状態 (定常状態) を定義する。

(2)

定常状態を対照群、またカオスエンジニアリングが実施された状態を実験群とする。『実験群では障害が起こる』という仮説の下、これを反証することを目指す。

(3)

実験群でカオスエンジニアリングを実施する。

(4)

対照群と比較し、『障害は起こる』という仮説を反証する。


07. ペネトレーションテスト

既知のサイバー攻撃を意図的に行い、システムの脆弱性を確認するテストのこと。

*例*

株式会社LACによるペネトレーションテストサービス

ペネトレーションテスト