テスト エクスプローラーを使用したネイティブ コードの単体テスト

Visual Studio では、C++ で記述されたアンマネージ コードの単体テストを作成できます。アンマネージ コードは、ネイティブ コードと呼ばれます。

次の手順では、立ち上げる必要な情報が含まれています。以下のセクションでは、手順を詳しく説明するチュートリアルです。

アンマネージ コードの DLL の単体テストを作成するには

  1. テストの他の Visual Studio プロジェクトを作成するには [Native Test Project] テンプレートを使用します。

    テスト プロジェクトは、サンプル コードが含まれています。

  2. DLL をテスト プロジェクトにアクセスできるようにする:

    • #include DLL の外部アクセスできる関数の申告を含む .h ファイル。

      .h ファイルは _declspec(dllimport)でマークされている関数の宣言を含める必要があります。また、DEF ファイルを使用してメソッドをエクスポートできます。詳細については、「インポートとエクスポート」を参照してください。

      単体テストはテスト対象の DLL からエクスポートされる関数のみアクセスできます。

    • テスト プロジェクトの参照に DLL プロジェクトを追加します:

      テスト プロジェクトの [プロパティ] では、[共通プロパティ][Framework と参照] を展開し、[参照の追加] を選択します。

  3. テスト プロジェクトで、テスト クラス、およびテスト メソッドをテスト マクロを使用してクラスを作成し、次の方法で保持する:

    #include "stdafx.h"
    #include <CppUnitTest.h>
    #include "..\MyProjectUnderTest\MyCodeUnderTest.h"
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    TEST_CLASS(TestClassName)
    {
    public:
      TEST_METHOD(TestMethodName)
      {
        // Run a function under test here.
        Assert::AreEqual(expectedValue, actualValue, L"message", LINE_INFO());
      }
    }
    
    • Assert はテストの結果を検証するために使用できる複数の静的関数が含まれています。

    • LINE_INFO() パラメーターは省略できます。PDB ファイルがない場合、テスト ランナーが失敗の位置を識別することができます。

    • セットアップと、テスト クリーンアップ メソッドを作成できます。詳細については、TEST_METHOD マクロの定義を開き、CppUnitTest.h のコメントを参照してください。

    • テスト クラスに入れ子にできません。

  4. テストの実行にテストのエクスプローラーの使用:

    1. [ビュー] で、メニューの [その他のウィンドウ][テスト エクスプローラー] を選択します。

    2. Visual Studio ソリューションをビルドします。

    3. テストのエクスプローラーで、[すべて実行] を選択します。

    4. テストをテストのエクスプローラーで詳しく調べる場合:

      1. エラー メッセージを表示およびスタック トレースなどの詳細を確認するテストの名前を選択します。

      2. エラーの位置またはテスト コードに移動するテストの名前 (たとえば) をダブルクリックして開きます。

      3. テストのショートカット メニューで、デバッガーでテストを実行するには [選択されたテストのデバッグ] を選択します。

チュートリアル: テストのエクスプローラーで、アンマネージ DLL の開発

独自の DLL を開発するには、このチュートリアルを同期できます。主な手順は次のとおりです:

  1. ネイティブのテスト プロジェクトを作成します。テストは、DLL から別のプロジェクトで開発している作成されます。

  2. DLL プロジェクトを作成します。このチュートリアルでは、新しい DLL を作成しますが、既存の DLL をテストする手順は似ています。

  3. DLL 関数をテストに表示されるようにします。

  4. 繰り返しテストをインクリメントします。ここでは、コードの開発とテストに沿った "Red" 緑リファクタリングのサイクルをお勧めします。

  5. 失敗したテストのデバッグ。デバッグ モードでテストを実行できます。

  6. テストを変更することなく中にリファクタリング。リファクタリングは、外部動作を変更せずにコードの構造の改良を意味します。コードのパフォーマンス、機能拡張、または読みやすさが向上するようにできます。意図が動作を変更できます。ではないため、コードのリファクタリングの変更を行っている最中にテストは変更されません。テストはリファクタリング中、バグがないことを確認できます。したがって、テストがない場合よりも多くの自信をもつこのような変更を加えることができます。

  7. 確認のカバレッジ。単体テストは、コードの多くを実行する場合に便利です。コードのどの部分をテストして使用されているかを確認できます。

  8. 外部リソースから分離単位。通常、DLL は、そのほかの DLL と同じように、データベースを開発しているサブシステム、またはリモート システム上の他のコンポーネントに依存しています。依存関係の分離の各単位をテストすると便利です。外部コンポーネントはゆっくりを実行できます。開発時に、他のコンポーネントが不完全である可能性があります。

ネイティブの単体テスト プロジェクトを作成します。

  1. [ファイル] メニューで、[新規][プロジェクト] クリックします。

    ダイアログ ボックスで、[インストール済み][テンプレート][Visual C++][テスト] を展開します。

    [Native Test Project] テンプレートを選択します。

    このチュートリアルでは、テスト プロジェクトが NativeRooterTestという名前です。

    C++ 単体テスト プロジェクトの作成

  2. 新しいプロジェクトに、unittest1.cppを検査します。

    TEST_CLASS と TEST_METHOD が表示されたテスト プロジェクト

    次の点に注意してください。

    • 各テストは TEST_METHOD(YourTestName){...}を使用して定義されます。

      従来の関数のシグネチャを記述する必要はありません。マクロ定義は TEST_METHOD によって作成されます。マクロはインスタンスの関数を呼び出さない void を返します生成されます。また、テスト メソッドに関する情報を返す静的関数を生成します。この情報は、テストのエクスプローラーがメソッドを見つけることができます。

    • テスト メソッドはクラスに TEST_CLASS(YourClassName){...}を使用してグループ化。

      テストの実行時、各テスト クラスのインスタンスが作成されます。テスト メソッドは、未指定の順序で呼び出されます。各モジュール、クラス、またはメソッドの前後に呼び出される特殊なメソッドを定義できます。詳細については、組織 C++ のテストを参照してください。

  3. テストの実行のエクスプローラーことを確認してください:

    1. テスト コードを挿入します:

      TEST_METHOD(TestMethod1)
      {
      Assert::AreEqual(1,1);
      }
      

      Assert のクラスがテスト メソッドの結果を検証するために使用できる複数の静的メソッドを提供することに注意してください。

    2. [テスト] で、メニューの [実行][すべてのテスト] を選択します。

      テストのビルドと実行。

      テストのエクスプローラーが表示されます。

      テストは [成功したテスト] の下に表示されます。

      1 つのテストが成功したことを示す単体テスト エクスプローラー

アンマネージ DLL プロジェクトを作成します。

  1. [Win32 プロジェクト] テンプレートを使用して [Visual C++] のプロジェクトを作成します。

    このチュートリアルでは、プロジェクト RootFinderはという名前です。

    C++ Win32 プロジェクトの作成

  2. Win32 アプリケーション ウィザードの[ [DLL][シンボルのエクスポート]

    [シンボルのエクスポート] のオプションはエクスポートするメソッドを宣言するために使用できる便利なマクロを生成します。

    [DLL] と [シンボルのエクスポート] が設定された C++ プロジェクト ウィザード

  3. プリンシパル .h ファイルのエクスポート関数を宣言する:

    API マクロを使用した新しい DLL コード プロジェクトと .h ファイル

    宣言子 __declspec(dllexport) は、クラスのパブリック メンバーとプロテクト メンバーを DLL の外部で表示される。詳細については、「C++ クラスの dllimport と dllexport を使用する」を参照してください。

  4. プリンシパル .cpp ファイルで、関数の最小の本体を追加します:

    // Find the square root of a number.
    double CRootFinder::SquareRoot(double v)
    {
      return 0.0;
    }
    

DLL プロジェクトにテスト プロジェクトをです。

  1. テスト プロジェクトのプロジェクト参照に DLL プロジェクトを追加します:

    1. テスト プロジェクトのプロパティを開き、[共通プロパティ][Framework と参照] を選択します。

      C++ プロジェクト プロパティ - Framework と参照

    2. [新しい参照の追加] を選択します。

      [参照の追加] のダイアログ ボックスでは、DLL プロジェクトを選択し、[追加] を選択します。

      C++ プロジェクト プロパティ - 新しい参照の追加

  2. プリンシパルの単体テスト .cpp ファイルで、DLL コードの .h ファイルが含まれています:

    #include "..\RootFinder\RootFinder.h"
    
  3. エクスポート関数を使用する基本的なテストを追加します:

    TEST_METHOD(BasicTest)
    {
    CRootFinder rooter;
    Assert::AreEqual(
    // Expected value:
    0.0, 
    // Actual value:
    rooter.SquareRoot(0.0), 
    // Tolerance:
    0.01,
    // Message:
    L"Basic test failed",
    // Line number - used if there is no PDB file:
    LINE_INFO());
    }
    
  4. ソリューションをビルドします。

    新しいテストは、エクスプローラーに表示されます。

  5. テストのエクスプローラーで、[すべて実行] を選択します。

    単体テスト エクスプローラー - 基本テスト成功

コードの実行の関数が Project テストを実行できることをテストおよびコード プロジェクトと認識されて設定します。これは実際のテストおよびコードの記述を開始できます。

繰り返しテストをインクリメントし、渡らせます

  1. 新しいテストを追加します:

    TEST_METHOD(RangeTest)
    {
      CRootFinder rooter;
      for (double v = 1e-6; v < 1e6; v = v * 3.2)
      {
        double actual = rooter.SquareRoot(v*v);
        Assert::AreEqual(v, actual, v/1000);
      }
    }
    
    ヒントヒント

    これは、合格したテストを変更しないことをお勧めします。代わりに、テストに成功します、次に別のテストを追加して、などのように、新しいテストを、更新され、コードが。

    ユーザーがそれぞれの条件を変更すると、その正しくないテストを無効にします。新しいテストを記述してインクリメント同じ方法で、一つずつ動作します。

  2. 次に、テストのエクスプローラーのソリューションを選択します [すべて実行] をビルドします。

    新しいテストは失敗します。

    RangeTest 失敗

    ヒントヒント

    それを書き込んだ直後に、各テストが失敗することを検証します。これは、失敗してテストを記述する簡単な誤りを回避できます。

  3. 新しいテストが成功すると、テスト対象コードを拡張する:

    #include <math.h>
    ...
    double CRootFinder::SquareRoot(double v)
    {
      double result = v;
      double diff = v;
      while (diff > result/1000)
      {
        double oldResult = result;
        result = result - (result*result - v)/(2*result);
        diff = abs (oldResult - result);
      }
      return result;
    }
    
  4. 次に、テストのエクスプローラーのソリューションを選択します [すべて実行] をビルドします。

    両方のテストのパス。

    単体テスト エクスプローラー - 範囲テスト成功

    ヒントヒント

    テストを一つずつ追加して、コードを開発します。すべてのテストが各反復後に渡すことを確認します。

失敗したテストのデバッグ

  1. 別のテストを追加します:

    #include <stdexcept>
    ...
    // Verify that negative inputs throw an exception.
    TEST_METHOD(NegativeRangeTest)
    {
      wchar_t message[200];
      CRootFinder rooter;
      for (double v = -0.1; v > -3.0; v = v - 0.5)
      {
        try 
        {
          // Should raise an exception:
          double result = rooter.SquareRoot(v);
    
          _swprintf(message, L"No exception for input %g", v);
          Assert::Fail(message, LINE_INFO());
        }
        catch (std::out_of_range ex)
        {
          continue; // Correct exception.
        }
        catch (...)
        {
          _swprintf(message, L"Incorrect exception for %g", v);
          Assert::Fail(message, LINE_INFO());
        }
      }
    }
    
  2. ソリューションをビルドし、[すべて実行] を選択します。

  3. (またはをダブルクリックします) 失敗したテストを開きます。

    アサーション エラーが強調表示されます。エラーのメッセージは、テストのエクスプローラーの詳細]ウィンドウに表示されます。

    NegativeRangeTest 失敗

  4. テストが失敗するかは、関数をステップ実行する方法:

    1. SquareRoot の関数の先頭にブレークポイントを設定します。

    2. 失敗したテストのショートカット メニューで、[選択したテストのデバッグ] を選択します。

      ブレークポイントで実行が停止すると、コードをステップ実行します。

  5. には、開発中の関数のコードを挿入します:

    #include <stdexcept>
    ...
    double CRootFinder::SquareRoot(double v)
    {
        // Validate parameter:
        if (v < 0.0) 
        {
          throw std::out_of_range("Can't do square roots of negatives");
        }
    
  6. すべてのテストが渡されます。

    すべてのテストの成功

リファクタリング テストを変更せずにコード

  1. SquareRoot 関数の計算全体を簡略化する:

    // old code:
    //   result = result - (result*result - v)/(2*result);
    // new code:
         result = (result + v/result)/2.0;
    
  2. ソリューションをビルドし、エラーが生じないように [すべて実行] を選択します。

    ヒントヒント

    コードを変更するときにバグが生じないような一連の単体テストが作成されます。

    他の変更とは別にリファクタリングを保持します。

次の手順

  • 分離ほとんどの DLL はデータベースなどの他のサブシステムやそのほかの DLL に依存しています。これらのコンポーネントは、並列開発されます。他のコンポーネントがまだ利用できませんが発生するように単体テストを割り当てるには、モックに置き換える必要があります

  • **ビルド確認テスト。**一定の間隔でチームのビルド サーバーで実行するテストを指定できます。これは、複数のチーム メンバーの作業が統合されたときにバグがもたらされないことを確認します。

  • **チェックインのテスト。**各チーム メンバーがソース管理にコードをチェックインする前にテストを実行することを必須とすることができます。これは通常、ビルド確認テストの完全なセットのサブセットです。

    また、コード カバレッジの最小を義務付けてできます。

参照

処理手順

Walkthrough: Creating and Using a Dynamic Link Library (C++)

概念

インポートとエクスポート

その他の技術情報

マネージとアンマネージ コードとの相互運用性の概要

ネイティブ コードのデバッグ