📘

テストの基本: テストと技法の種類、Test Double(stub,mock)について。

2024/02/25に公開
2

テストの基本のキ!

今回は、テストの基本のキと題して、
テストの種類と技法の種類、そしてTest Double(stub,mock) について書いていきます。

なんとなくテストコード真似して書いていたみてたけど(それがダメや)
"stubとmockの違いわかる?"と聞かれて、stubを知らなかったのも恥ずかしかった...苦笑
(最初は当たり前かもしれない...!)

では以下の項目で書いていきます!!

  1. テストの種類について
    Unitテストって?
  2. テストの技法について
    ・ ブラックボックス・ホワイトボックス
  3. Test Doubleについて
    ・ stubとmockの違いを説明できる?
  4. stubとドライバについて

種類について

テストの種類には、単体テスト、結合テスト、機能テスト、受け入れテストの4つがある。
tableでまとめます。

テストの種類 対象 目的
単体テスト (Unit Testing) 機能単体のテスト
最小の単位 (関数やメソッド)
コードの機能を個別に検証する。
プログラムが設計書通り動くのか
結合テスト (Integration Testing) 機能同士を組み合わせたテスト
複数のモジュールやコンポーネント
モジュール間の連携や相互作用を検証する
機能テスト (Functional Testing) システムの機能全体のテスト システムの特定の機能が要件通りに動作するか検証する
受け入れテスト (Acceptance Testing) システム全体 ユーザーが要求した機能や要件を満たしているか検証する

この中で今日はユニットテストについて抜き出して書いていきたいと思う。

Unitテストについて

<要点要約>

  • クラスやメソッドを対象としたコードの機能を個別に検証するためのテスト
    (アプリケーション全体の中から1つの部分 (通常は単一のクラスや関数) だけを
    完全に取り出して実行するテスト.)
  • ソフトウェアテストの中で最も小さい粒度(=モジュール)のテストであり、
    単体テストのメリットはその速度と不具合の発見や修正のしやすさ。
  • ホワイトボックステストを行うことが多い。
  • 単体テスト自体の品質を示す指標=「カバレッジ

カバレッジ(Coverage)とは: 
日本語では、"網羅率"と言って
コードの実行時にどれだけの部分がテストされたかを示す数値

行うメリットとガバレッジについて

100%のカバレッジを達成することに意味はあるのか

答えはNOで、カバレッジは80くらいが目標とされてます。
100%狙うということは...以下のデメリットが発生します。

  • 時間とリソースの浪費:
     100%のカバレッジを達成するためには多くの時間とリソースが必要
  • 過剰なテストの作成:
     カバレッジを完全に網羅するために、本来必要のないテストケースが追加される可能性がある。
  • 保守性の低下:
     テストスイートが複雑化し、保守性が低下する可能性があります。

テストの技法について

ブラックボックステスト ホワイトボックステスト
対象 システムの外部動作 システムの内部構造やコード
焦点 入力と出力 プログラムのロジックや制御フロー
要件 仕様書やユーザー要求仕様に基づく ソースコードや設計仕様に基づく
テスターの知識 システムの機能や要件に関する知識が必要 プログラミング言語やアルゴリズムに関する知識が必要
利点 実装の詳細を知らなくてもテストできる 内部のロジックやエラーを特定しやすい
欠点 実装の詳細が不明なため、不具合の特定が難しい 全ての経路や条件を網羅することが難しい
結合テストやシステムテストで採用することが多い 単体テストで行うことが多い

▷ ブラックボックステスト

ブラックボックステストは、システムの外部動作をテストする技法で、
テストケースは主に仕様書やユーザー要求仕様に基づいて設計される。

外部動作をテストするものなので、
テスターはシステムの内部構造や実装の詳細を知らなくてもテスト実施可能。
主に結合テストやシステムテストで採用されることが多い。

▷ ホワイトボックステスト

ホワイトボックステストは、システムの内部構造やコードをテストする技法で、
主にソースコードや設計仕様に基づいて設計される。

内部構造やコードの正確性を見るため、
テスターはプログラミング言語やアルゴリズムに関する知識が必要。
(実際には実装者が行うことが多い。)
主に単体テストで行われることが多い

Test Double: stub(スタブ)とmock(モック)

Test Doubleとは

  • 実際のオブジェクトを置き換えるためのテクニックやパターンを指す総称的な用語。
  • テスト対象が依存している外部のコンポーネントと置き換わるもの。
  • Gerard Meszarosの『xUnit Test Patterns』に提唱されているもの。

    xUnit Test Patterns:
    上記リンクは、Gerard Meszarosによって開発され、著書『xUnit Test Patterns』の内容を補足するために作成されたページ。
    ソフトウェアテストにおけるパターンとベストプラクティスに焦点を当てた書籍。
    テスト自動化フレームワークのxUnit(ex. JUnit,NUnit,PHPUnit etc...)を使用した自動テストの作成パターン.
    この本は、テストコードの品質を向上させ、テストスイートの保守性や効率性を高めるための実践的なガイドとして評価されている。

  • Gerard Meszaros(ジェラード・メサロス)は5つの種類を提唱している。
    (主に外部への入出力の形の違いで分類されている)
  • 今回はその中でも同義にされやすいstab(スタブ)とmock(モック)について書いていく!

stub(スタブ)とmock(モック)

<要約>
実際のコンポーネントやオブジェクトの代替として使用されることは共通で、違いは...
スタブはテスト対象の入力を操作し、テスト対象に適切な振る舞いをさせるためのもので、
モックはテスト対象の外部依存関係の振る舞いを検証するもの。

Stub (スタブ) Mock (モック)
定義 未完成の機能の代わりとなる部品。 クラスの動作をシュミレートするためのオブジェクト。
動作 呼び出されたメソッドに設定された値や動作を返す。 呼び出されたメソッドがどのように動作し、何を返すかを定義する。
使用目的 テスト中に依存する部品の振る舞いを制御し、テストを容易にする。 テスト中にテスト対象のクラスが利用する外部依存関係の動作をシミュレートする。
実装 JUnitで実装可能。 通常、外部ライブラリを使って実装する。 ex. mockK
機能 テスト対象のクラスにおいて、まだ完成していない機能の代替を提供する。 テスト対象のクラスが呼び出している他のクラスや依存関係をシミュレートする。

stub


xUnit Patterns:Test Stub

A Temporary Test Stub is a Test Stub that is used to stand in for a depended-on component (DOC) that is not yet available. It typically consists of an empty shell of a real class with hard-coded return statements. As soon as the real DOC is available, it is used instead. Test-driven development often causes us to create Temporary Test Stubs as we write code from the outside inwards; these shells evolve into the real classes as we add code to them. In the need-driven development we tend to use Mock Objects because we want to verify that the SUT calls the right methods on the Temporary Test Stub and we typically keep using the Mock Object even after the real DOC is available.
Variation: Temporary Test Stubより

  • 入力内容を操作
  • 入力値をテストコードで実装して、呼び出されたメソッドに設定された値や動作を返す
  • 未完成の機能の代わりとなる部品

mock


xUnit Patterns: Mock Object

We can use a Mock Object as an observation point that is used to verify the indirect outputs of the SUT as it is exercised. Typically, the Mock Object also includes the functionality of a Test Stub in that it must return values to the SUT if it hasn't already failed the tests but the emphasis(My mother grew up in Hungary and has retained a part of her Hungarian accent -- think Zsa Zsa Gabor -- all her life. She says "It is important to put the emphasis on the right sylable.") is on the verification of the indirect outputs. Therefore, a Mock Object is lot more than just a Test Stub plus assertions; it is used a fundamentally different way.

  • 出力の操作
  • テスト対象内の外部コンポーネンへの出力の期待結果をセット
  • 実行時はそのセットした出力を取得して 成功しているのか?テスト

stubとドライバについて: 結合テスト

一番上で、テストの種類について書きましたが、ここでは結合テストが関係してくるので、
結合テストについても書いていきます。

トップダウンテストとボトムアップテスト

トップダウンテスト ボトムアップテスト
テスト開始の順序 上位レベルのモジュールから開始 下位レベルのモジュールから開始
テストの進行順序 下位レベルのモジュールを段階的に組み込んでいく 上位レベルのモジュールを段階的に組み込んでいく
未完成のモジュールの代わりに使用するもの スタブ ドライバ
スタブとドライバの役割 スタブは下位レベルのモジュールの動作を模倣する。 ドライバは上位レベルのモジュールの動作を制御する。


画像はこの方のがわかりやすかったです!

stubとドライバは、共通点として、
テストの実行時に未完成の部分を代替するために使用されるもので、
どちらも未完成の部分の振る舞いを模倣してるもので、他の部分のテストを可能にするもの。

  • stub:
    下位レベルのモジュールの代わりに使用される。(下位レベルのモジュールの振る舞いを模倣)
  • ドライバ:
    上位レベルのモジュールの代わりに使用される。(上位レベルのモジュールの動作を制御)

Discussion

HikaruooHikaruoo

突然のコメント失礼します。テストの基本やTest Doubleについて丁寧に解説していて初心者にはとてもありがたいです。ユニットテストでのstubとmockの違いを理解するのって確かに難しいですが、しっかり説明されていて勉強になります。テストの効率化には便利なツールが欠かせないと思いますが、ECHOAPIを使えばVS Code内でサクッとAPIのモック作成ができて、テストがさらに楽しくなるかもしれません

AirichanAirichan

コメントありがとうございます!

テストの効率化には便利なツールが欠かせない

そうですね...!ツールについてもまとめてみたいと思います!🧐✨