【C++】UnitTest(C ++用Microsoft単体テストフレームワーク/vstest.Console.exe)の使い方概要


UnitTest関連記事

やりたいこと

C++で作成したDLLがエクスポートしている関数の単体テスト(UnitTest)を行いたい。

概要

VisualStudio(2017)で単体テストプロジェクトを作成し、そこで単体テストを行う。

やること

プロジェクト作成

DLL作成用のプロジェクトを含むソリューションに、単体テスト用プロジェクトを追加する。

テスト対象のdllの必要物を参照設定する

C++で作成したDLLをC++で呼ぶでやったように、テストしたいDLLを使えるようにする。
(.libが見えるようにリンカの設定をし、DllImportをするための.hが見えるようにインクルードフォルダの設定をする)

単体テスト用コードを作成

初期状態で、下記のようなコードが作成される。

unittest1.cpp
#include "stdafx.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest1
{       
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(TestMethod1)
        {
            // TODO: テスト コードをここに挿入します
        }

    };
}

ここに、以前作成したDLLを呼ぶコードを追加する。
(もとのDLLはこちらを参照)※単体テスト用に関数をいくつか追加。


DLLの関数を、下記のようにテストコードで呼び出す。

unittest1.cpp
#include "stdafx.h"
#include "CppUnitTest.h"

#include "DllTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTestCpp
{       
    TEST_CLASS(UnitTest1)
    {
    public:

        BEGIN_TEST_METHOD_ATTRIBUTE(TestMethod_Normal)
            TEST_PRIORITY(1)
        END_TEST_METHOD_ATTRIBUTE()

        TEST_METHOD(TestMethod_Normal)
        {
            wchar_t* buf_in = L"あいうえお";
            wchar_t* buf_out = nullptr;

            int ans1 = Test_MyApiAdd(1, 2);
            int ans2 = Test_MyApiSub(3, 1);
            Test_MyApiPointerCopy(buf_in, &buf_out);

            Assert::AreEqual(ans1, 1 + 2); // 正常に終了
            Assert::AreEqual(ans2, 3 - 1); // 正常に終了
            Assert::IsNotNull(buf_out);    // 正常に終了

            Logger::WriteMessage("Test OK");// デバッグ時のログ(出力欄)に出力
        }

        BEGIN_TEST_METHOD_ATTRIBUTE(TestMethod_Error)
            TEST_PRIORITY(1)
        END_TEST_METHOD_ATTRIBUTE()

        TEST_METHOD(TestMethod_Error)
        {
            wchar_t* buf_in = nullptr;
            wchar_t* buf_out = nullptr;

            int ans1 = Test_MyApiAdd(1, 2);
            int ans2 = Test_MyApiSub(3, 1);
            Test_MyApiPointerCopy(buf_in, &buf_out);

            Assert::AreEqual(ans1, 1 + 5);    // ans1と1+5が一致しないので、ここでTestストップ。
            Assert::AreEqual(ans2, 100 - 1);  // 実施されない
            Assert::IsNotNull(buf_out);       // 実施されない

            Logger::WriteMessage("Test OK");
        }
    };
}

DLLの関数のコードは今回はこんな感じ。
足し算、引き算、文字列へのポインタをコピーする、だけの関数。

DllTest.cpp

int __cdecl Test_MyApiAdd(int p1, int p2)
{
    return p1 + p2;
}

int __cdecl Test_MyApiSub(int p1, int p2)
{
    return p1 - p2;
}

void __cdecl Test_MyApiPointerCopy(wchar_t* p_in, wchar_t** p_out)
{
    if (p_in != nullptr)
    {
        *p_out = p_in;
    }
    else
    {
        p_out = nullptr;
    }
}

Assert

「Assert::AreEqual()」などのモジュールを使って、テスト対象の関数の戻り値などが正しい値かどうかを確認する。下記のようなものがある。

モジュール名 役目
AreEqual オブジェクトが一致することを確認する
AreNotEqual オブジェクトが一致しないことを確認する
IsNull オブジェクトがNULLであることを確認する
IsNotNull オブジェクトがNULLでないことを確認する

など。ほかにも多数ある。

詳しくは、MSのページを参照。

Attribute

テスト用メソッドに対して、Attributeを設定できるらしいが、どうやって使うかはっきりわからず。詳しくは、MSのページを参照。

VisualStudio上でUnitTestを実施

[テスト] > [実行] の中のメニューを選んで、UnitTestを実施する。
または、[テスト] > [ウインドウ] > [テストエクスプローラ] でテストエクスプローラを開き、そこでもテストの実行ができる。

[実行]ではなく、[デバッグ]をすると、UnitTestのコード上でBreakを貼ったり、step実行ができる。

コンソールでUnitTestを実施

必要物をダウンロード

テストエージェントvstest.console.exeが必要。下記の「VisualStudio2019のツール」からダウンロードする。

https://visualstudio.microsoft.com/ja/downloads/?q=agents

コンソールで実施

インストール後、「VSTest.Console.exe 」を使用して、テストを行う。
書式は、

vstest.console.exe "UnitTestのプロジェクトが吐いたDLL" "オプション"

UnitTest用.bat
rem Unitテスト実施用bat
rem x86用 ログを出力
rem ログは、「カレントディレクトリ\TestResults」に出力される
cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\"
vstest.console.exe "C:\Users\masa\Documents\myTortoiseGit\WPF-\020_CppDllProject\Debug\UnitTestCpp.dll" /platform:x86 /inIsolation /Logger:trx
pause

※注意※
上のbatでは、vstest.console.exeのあるフォルダとしてC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\としているが、VisualStudioを入れずに上のダウンロードからVSTESTのエージェントだけを入れた場合は、フォルダが別になる。その場合は、パスを自分のPCにあったものにすること。
例)私のPCの場合は下記にあった。
C:\Program Files (x86)\Microsoft Visual Studio\2019\TestAgent\Common7\IDE\Extensions\TestPlatform\vstest.console.exe

実行すると、このような窓が表示される。

ログは、カレントディレクトリにできた「TestResults」フォルダ内に保存される。
.trxファイルを開くと、VisualStudioで結果を見ることができる。

※BEGIN_TEST_METHOD_ATTRIBUTEで設定したTEST_PRIORITYの値は、この結果で見れるっぽい。vstestの実行パラメータに、優先順位を指定できるので、そこに生きると思われる。(未検証)

C#のUnitTestについて

C++とほとんど同じやり方でUnitTestできる。下記のページを参照。

MsTestによるユニットテストの解説

https://qiita.com/mima_ita/items/55394bcc851eb8b6dc24
VSの設定からプロジェクトの設定、コードの書き方まで詳しく書いてくれている。
これ見れば一通りできそう。(コマンドラインでの実施も書いてくれている)

MS docs

公式ページ。単体テストのやり方はいくつかあるらしく(MSTestとか、xUnitとか)、その説明が書かれたページ。

MSTestのコマンドラインパラメータの一覧

参照(C++)

Visual StudioでC ++用のMicrosoft単体テストフレームワークを使用する

Microsoft.VisualStudio.TestTools.CppUnitTestFramework APIリファレンス(Assertとか、Attributeとか)
https://docs.microsoft.com/ja-jp/visualstudio/test/microsoft-visualstudio-testtools-cppunittestframework-api-reference?view=vs-2019#cppUnitTestAssert_h