CppUTestは、単体テストを自動化するためのフリーソフトウェアです。
C/C++は非常に自由度が高く何でもできる反面、ちょっとしたミスですぐに不具合を起こします。このためソースコードレベルでテストを行うことが必須となります。これを行うのが単体テストです。テストを記述するのはとても面倒で億劫な作業です。しかし一度テストを記述すれば、そのあとはボタン1つで何度でもテストを実行できるのです。
皆さん何度か経験があるのではないでしょうか。手を加えた箇所と無関係だからと、手間なテストを怠ったことで不具合を起こしたことを。CppUTestは、このようなトラブルを防いでくれるかもしれないツールです。
必要なもの
- CMake
-
下記にしたがってダウンロードからインストールまで行います。
CMakeのダウンロードからインストールまで CMakeは「CMakeLists.txt」を読み込んでビルドを自動化するフリーソフトウェアです。 当サイト内ではCMakeを直接使用することはないので、インストール方法までを紹介し… - eclipse
-
下記にしたがってダウンロードからインストールまで行います。
eclipseのダウンロードからインストールまで eclipseは数々のプログラミング言語に対応した、フリーの統合開発環境(IDE)です。プラグインを導入することで様々な機能を拡張できる、汎用性の高いIDEとなっています… - CppUtest Test Runner
-
eclipseでCppUTestを使用するためのプラグインです。
STEP下記サイトにアクセスします。GitHub – tcmak/CppUTestEclipseJunoTestRunner: CppUTest Test Runner for Eclipse Juno or above CppUTest Test Runner for Eclipse Juno or above. Contribute to tcmak/CppUTestEclipseJunoTestRunner development by creating an account on GitHub.STEP下図①②の順に操作し、zipファイルをダウンロードします。 - CppUTest
-
STEP下記サイトにアクセスします。GitHub – cpputest/cpputest: CppUTest unit testing and mocking framework for C/C++ CppUTest unit testing and mocking framework for C/C++ – cpputest/cpputestSTEP「Releases」をクリックします。STEP「Assets」をクリックします。STEPzipファイルをダウンロードします。
インストール
- CppUtest Test Runner
-
STEP「C:\eclipse\dropins」を開きます。STEP「CppUTest」フォルダーを作成します。STEPダウンロードしたzipファイルを解凍し、「org.eclipse.cdt.testsrunner.cpputest」フォルダーを開きます。
「org.eclipse.cdt.testsrunner.cpputest」フォルダー内にある下記のフォルダーやファイルを、「C:\eclipse\dropins\CppUTest」フォルダーに移動します。
- binフォルダー内にあるorgフォルダー
- META-INFフォルダー
- plugin.propertiesファイル
- plugin.xmlファイル
STEP移動後のフォルダー内の構成は下図のとおりになります。STEPコマンドプロンプトを起動し、「C:\eclipse」フォルダーに移動します。STEP「eclipse.exe -clean」を実行します。 - CppUTest
-
STEPダウンロードしたzipファイルを解凍します。STEP解凍してできたフォルダー名を「CppUTest」に変更します。STEPCppUTestフォルダーをCドライブの直下に置きます。STEPスタートメニューから①コマンドプロンプトを探し出して右クリックし、「管理者として実行」をクリックします。STEP「cd C:\CppUTest\cpputest_build」と入力してEnterキーを押します。STEP「cmake -G “MinGW Makefiles” ..」と入力してEnterキーを押します。STEP「mingw32-make」と入力してEnterキーを押します。STEP「mingw32-make install」と入力してEnterキーを押します。STEP環境変数に新規で「CPPUTEST_HOME」「C:\Program Files (x86)\CppUTest」を追加します。STEPWindowsを再起動します。
eclipseの初期設定
eclipseでCppUTestを使えるようにするための設定を行います。
CppUTestによるテスト
プロジェクトの作成
プロジェクトの設定
プロジェクトの構成例
下記のようなプロジェクト構成であったとします。
C:\workspace
└ CppUTest
└ src
├ AllTests.cpp ... テストコード
├ base64Test.cpp ... テストコード
├ base64.c ... テスト対象
└ base64.h ... テスト対象
[base64.c]:テスト対象のソースコード
//! Base64エンコードテーブル
static const uint8_t m_enc_table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/** ----------------------------------------------------------------------------
* @brief Base64エンコード
*
* @param [in] bin : バイナリーデータ
* @param bin_size : バイナリーデータ長
* @param [out] ascii : ASCIIデータ
* @return ASCIIデータ長
*/
int32_t base64_encode(const uint8_t bin[], uint32_t bin_size, uint8_t ascii[])
{
uint8_t bit6;
uint8_t buf_size = 0;
uint16_t buf = 0;
uint32_t ascii_size = 0;
for (uint32_t i = 0; i < bin_size; i++) {
buf = (uint16_t)(buf << 8) | bin[i];
buf_size += 8;
// 6ビット毎に変換
do {
bit6 = (uint8_t)(buf >> (buf_size - 6)) & 0x3f;
buf_size -= 6;
ascii[ascii_size] = m_enc_table[bit6];
ascii_size++;
} while (buf_size >= 6);
}
// 端数ビットがある場合は0を補完して変換
if (buf_size > 0) {
bit6 = (uint8_t)(buf << (6 - buf_size)) & 0x3f;
ascii[ascii_size] = m_enc_table[bit6];
ascii_size++;
}
// バイト数が4の倍数でないなら'='を追加
while ((ascii_size % 4) != 0) {
ascii[ascii_size] = (uint8_t)'=';
ascii_size++;
}
ascii[ascii_size] = (uint8_t)'\0';
return (int32_t)ascii_size;
}
[AllTests.cpp]:何も考えずにこのファイルを作成してください。
#include "CppUTest/CommandLineTestRunner.h"
int main(int argc, char *argv[])
{
return CommandLineTestRunner::RunAllTests(argc, argv);
}
[base64Test.cpp]:「base64.c」ファイル用のテストコードです。
#include "CppUTest/TestHarness.h" // 必要なもの
#include <string.h>
#include "base64.h"
// テストグループとテストグループ内の各テストを実行する前後に行う処理を定義します
// ( )内の"base64"は識別子で、テスト対象のファイル名にすると良いでしょう
TEST_GROUP(base64){
// 各テストケースの実行直前に呼ばれる仮想メソッド
TEST_SETUP(){
}
// 各テストケースの実行直後に呼ばれる仮想メソッド
TEST_TEARDOWN(){
}
};
// 実行するテストを記述します
// "base64"はTEST_GROUPと同じ識別子で、"Test_base64_encode"はテストの識別子です
TEST(base64, Test_base64_encode)
{
uint8_t bin[128];
uint8_t ascii[128];
int32_t size;
strncpy((char *)bin, "ABCDE", 5);
size = base64_encode(bin, 5, ascii);
LONGS_EQUAL(size, 8); // テスト1
STRNCMP_EQUAL((char *)ascii, "QUJDREU=", size); // テスト2
}
// 他の関数のテストも行うなら、TESTを分けると良いでしょう
TEST(base64, Test_base64_decode)
{
uint8_t bin[128];
uint8_t ascii[128];
int32_t size;
// 成功パターン
strncpy((char *)ascii, "QUJDREU=", 8);
size = base64_decode(ascii, 8, bin);
LONGS_EQUAL(size, 5);
STRNCMP_EQUAL((char *)bin, "ABCDE", size);
}
プロジェクトの実行
また②にはテストの一覧が表示されています。この中で誤りの発生したテストは、アイコンの左下に青色で小さく「×」と表示されます。そこをダブルクリックしていくとテストに引っ掛かった箇所へ移動できるので、誤りを訂正してください。
TESTマクロ
TESTマクロリスト
CppUTestが用意しているTESTマクロです。CppUTestではこれらのマクロを駆使して単体テストを行います。
- CHECK(boolean condition)
-
ブール結果がtrueかをチェックします。
- CHECK_FALSE(condition)
-
ブール結果がfalseかをチェックします。
- STRCMP_EQUAL(expected, actual)
-
strcmpを使用して、文字列が等しいかをチェックします。
- STRNCMP_EQUAL(expected, actual, length)
-
strncmpを使用して、文字列が等しいかをチェックします。
- STRCMP_NOCASE_EQUAL(expected, actual)
-
大文字と小文字を区別せずに、文字列が等しいかをチェックします。
- STRCMP_CONTAINS(expected, actual)
-
actualにexpectedが含まれているかをチェックします。
- LONGS_EQUAL(expected, actual)
-
2つの数値を比較します。
- UNSIGNED_LONGS_EQUAL(expected, actual)
-
2つの正の数を比較します。
- LONGLONGS_EQUAL(expected, actual)
-
2つの数値を比較します。
- UNSIGNED_LONGLONGS_EQUAL(expected, actual)
-
2つの正の数を比較します。
- BYTES_EQUAL(expected, actual)
-
8ビット幅の2つの数値を比較します。
- POINTERS_EQUAL(expected, actual)
-
2つのポインターを比較します。
- DOUBLES_EQUAL(expected, actual, tolerance)
-
2つの浮動小数点数が許容範囲内(tolerance)かを比較します。
- FUNCTIONPOINTERS_EQUAL(expected, actual)
-
2つのvoid(*)関数ポインターを比較します。
- MEMCMP_EQUAL(expected, actual, size)
-
メモリーの2つの領域を比較します。
- BITS_EQUAL(expected, actual, mask)
-
マスクを適用して、期待値と実際のビットを少しずつ比較します。
TESTマクロの使用例
CHECK(true); // 判定値がtrueなら合格
CHECK_FALSE(false); // 判定値がfalseなら合格
STRCMP_EQUAL("abc", "abc"); // 文字列が一致すれば合格
STRNCMP_EQUAL("abc", "abc", 3); // 文字列が一致すれば合格
STRCMP_NOCASE_EQUAL("abc", "ABC"); // 大文字・小文字を区別せず一致すれば合格
STRCMP_CONTAINS("123", "ABC123"); // 文字列が含まれていれば合格
// 数値が一致すれば合格
LONGS_EQUAL(-1, -1);
UNSIGNED_LONGS_EQUAL(1, 1);
LONGLONGS_EQUAL(-1, -1);
UNSIGNED_LONGLONGS_EQUAL(1, 1);
BYTES_EQUAL(-1, 255);
DOUBLES_EQUAL(1.000, 1.001, 0.001);
BITS_EQUAL(0x31, 0x01, 0x0F);
MEMCMP_EQUAL("string", "string", 6);
// ポインターが一致すれば合格
POINTERS_EQUAL(0, 0);
FUNCTIONPOINTERS_EQUAL(0, 0);
その他テストコードのサンプル
CppUTestタグのある記事には、テストコードのサンプルがあります。それらも参考にしてください。