手動単体テストの実装の背後にあるアーキテクチャは何ですか? 実行または失敗のパスに基づいてそれに応じて値を返す場合、それらの返された値がそれを効果的に解釈するにはどうすればよいですか? C言語関連の回答をお願いします。
2 に答える
C での単体テストについては、xUnit フレームワークで機能するのと同じように考えることをお勧めします。
xUnit では、テストは「スイート」にグループ化され (テストされるクラスごとに 1 つのスイートが一般的です)、関数ごとに 1 つ以上のテストがあります。setup 関数はスイート内のテストが実行される前に呼び出され、teardown 関数はそのスイート内のすべてのテストが完了した後に呼び出されます。
あなたの言語にはクラスがないので、これらの関数ポインターを関数ポインターの構造体に格納でき、それらの配列を繰り返し処理して、セットアップ、テスト、分解を行うことができます。
必要に応じて、単体テスト フレームワークを導入することもできます。C言語で利用できるものはたくさんあります。ウィキペディアで一覧をご覧いただけます。
すべてを大規模で公式なものにしたくない場合は、完全に C で実装された単純な単体テスト フレームワークの例と、いくつかの単体テストのサンプルを含む「追加」アプリケーションの例を次に示します。テストの 1 つは意図的に失敗するように設計されているため、失敗したテストがどのように応答するかを確認できます。最後に、テスト実行アプリケーションの例があります。単体テスト フレームワークは、非常に効果的であるためにすべてが大きく重いものである必要はありません。
これら 2 つのモジュールは、テスト フレームワーク全体です。
testFramework.h
/* testFramework.h */
#pragma once
typedef struct
{
int(*test)();
} UNITTEST;
typedef struct
{
void(*setup)();
void(*teardown)();
UNITTEST *tests;
} UNITTESTSUITE;
extern int callTest(UNITTEST *test);
extern int callTestSuite(UNITTESTSUITE suite);
extern void testFailed(const char* testName, const int testLine, const char* message);
#define TESTFAILED(X) testFailed(__FILE__, __LINE__, X)
testFramework.c
/* testFramework.c */
#include <stdio.h>
#include <stdlib.h>
#include "testFramework.h"
int callTest(UNITTEST *test)
{
return (*test).test();
};
int callTestSuite(UNITTESTSUITE suite)
{
int rc = 1;
UNITTEST* test = suite.tests;
if (suite.setup)
(suite.setup());
while (test->test != 0)
{
if (callTest(test++))
{
printf(".");
}
else
{
printf("#");
rc = 0;
}
}
if (suite.teardown)
(suite.teardown());
printf("\n");
return rc;
}
void testFailed(const char* testName, const int testLine, const char* message)
{
fprintf(stderr, "%s(%i): ERROR test failed, %s\n", testName, testLine, message);
};
テストが必要なアプリケーション コードは次のとおりです。
追加.h
/* addition.h */
#pragma once
extern int add(int x, int y);
追加.c
/* addition.c */
#include <stdio.h>
#include <stdlib.h>
int add(int x, int y)
{
return x+y;
};
私のアプリケーションが機能することを証明する単体テストを次に示します。
追加Tests.h
/* additionTests.h */
#pragma once
#include "testFramework.h"
extern void setupAdd();
extern void teardownAdd();
extern int testAddPositives();
extern int testAddFaultyTest();
extern int testAddNegatives();
extern int testAddMixed();
extern int testAddZeroes();
extern UNITTEST additionTests[];
extern UNITTESTSUITE additionSuite;
追加Tests.c
/* additionTests.c */
#include <stdio.h>
#include <stdlib.h>
#include "testFramework.h"
#include "addition.h"
void setupAdd()
{
return;
};
void teardownAdd()
{
return;
};
int testAddPositives()
{
int x=2, y=3;
int expected = 5;
int actual;
actual = add(x,y);
if (actual != expected)
{
TESTFAILED("actual not equal expected");
return 0;
}
return 1;
};
int testAddFaultyTest()
{
int x=2, y=2;
int expected = 5;
int actual;
actual = add(x,y);
if (actual != expected)
{
TESTFAILED("actual not equal expected");
return 0;
}
return 1;
};
int testAddNegatives()
{
int x=-2, y=-3;
int expected = -5;
int actual;
actual = add(x,y);
if (actual != expected)
{
TESTFAILED("actual not equal expected");
return 0;
}
return 1;
};
int testAddMixed()
{
int x=2, y=-3;
int expected = -1;
int actual;
actual = add(x,y);
if (actual != expected)
{
TESTFAILED("actual not equal expected");
return 0;
}
return 1;
};
int testAddZeroes()
{
int x=0, y=0;
int expected = 0;
int actual;
actual = add(x,y);
if (actual != expected)
{
TESTFAILED("actual not equal expected");
return 0;
}
return 1;
};
/* add each additional unit test to this array */
UNITTEST additionTests[] = {&testAddPositives, &testAddFaultyTest, &testAddNegatives, &testAddMixed, &testAddZeroes, 0 };
UNITTESTSUITE additionSuite = {&setupAdd, &teardownAdd, additionTests};
最後に、これが私のテスト フレームワーク アプリケーション ランナーです。
testMain.c
/* testMain.c */
#include <stdio.h>
#include <stdlib.h>
/* include the unit test .h files here */
#include "additionTests.h"
int main(int argc, char**argv)
{
/* call each unit test suite here */
if (callTestSuite(additionSuite))
return 0;
return 2;
};