標籤:

C++單元測試如何實施?


library: Gac Library -- C++ Utilities for GPU Accelerated GUI and Script

cases: https://gac.codeplex.com/SourceControl/latest#Common/UnitTest/UnitTest/TestList.cpp


學長給的手寫的框架

可以當作參考

PS: 我注釋掉了顏色信息 貌似windows失敗了

//*****test.h******

#ifndef TEST_HPP_INCLUDED

#define TEST_HPP_INCLUDED

#include &

#include &

#include &

#include &

#include &

#define TEST_DEBUG

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

#define INFEASIBLE -1

#define LOVERFLOW -2

typedef int Status;

//#define RESET "33[0m"

//#define BLACK "33[30m" /* Black */

//#define RED "33[31m" /* Red */

//#define GREEN "33[32m" /* Green */

//#define YELLOW "33[33m" /* Yellow */

//#define MAGENTA "33[35m" /* Magenta */

//#define CYAN "33[36m" /* Cyan */

//#define WHITE "33[37m" /* White */

//#define BOLDBLACK "33[1m33[30m" /* Bold Black */

//#define BOLDRED "33[1m33[31m" /* Bold Red */

//#define BOLDGREEN "33[1m33[32m" /* Bold Green */

//#define BOLDYELLOW "33[1m33[33m" /* Bold Yellow */

//#define BOLDBLUE "33[1m33[34m" /* Bold Blue */

//#define BOLDMAGENTA "33[1m33[35m" /* Bold Magenta */

//#define BOLDCYAN "33[1m33[36m" /* Bold Cyan */

//#define BOLDWHITE "33[1m33[37m" /* Bold White */

#define TESTCASE_NAME(testcase_name)

testcase_name##_TEST

#define TEST(testcase_name)

class TESTCASE_NAME(testcase_name) : public TestCase

{

public:

TESTCASE_NAME(testcase_name)(const char* case_name) : TestCase(case_name){};

virtual void Run();

private:

static TestCase* const testcase_;

};

TestCase* const TESTCASE_NAME(testcase_name)

::testcase_ = UnitTest::GetInstance()-&>RegisterTestCase(

new TESTCASE_NAME(testcase_name)(#testcase_name));

void TESTCASE_NAME(testcase_name)::Run()

#define RUN_ALL_TESTS()

UnitTest::GetInstance()-&>Run();

//單元測試的主體

class TestCase

{

public:

TestCase(const char *case_name) : testcase_name(case_name) {};

virtual void Run() = 0;

bool test_resu<

const char *testcase_name;

};

class UnitTest

{

public:

static UnitTest* GetInstance();

TestCase* RegisterTestCase(TestCase *testcase);

bool Run();

TestCase *current_test_case;

bool test_resu<

int passed_num;

int failed_num;

std::vector& testcases_;

};

UnitTest* UnitTest::GetInstance()

{

static UnitTest instance;

return instance;

}

TestCase* UnitTest::RegisterTestCase(TestCase *testcase)

{

testcases_.push_back(testcase);

return testcase;

}

bool UnitTest::Run()

{

test_result = true;

std::cout /*&<&< YELLOW*/ &<&< "[ Start Run ]" &<&< /*RESET &<&<*/ "Have " &<&< testcases_.size() &<&< " Unit Testing" &<&< std::endl;

std::cout &<&< std::endl;

for (std::vector&::iterator it = testcases_.begin(); it != testcases_.end(); ++it)

{

TestCase *test_case = *it;

current_test_case = test_case;

current_test_case-&>test_result = true;

std::cout &<&< /*GREEN &<&<*/ "[ Run ]" &<&< /*RESET &<&<*/ test_case-&>testcase_name &<&< std::endl;

test_case-&>Run();

if (test_case-&>test_result)

std::cout &<&< /*GREEN &<&<*/ "[ Pass ]" &<&< /*RESET &<&<*/ test_case-&>testcase_name &<&< std::endl;

else

std::cout &<&< /*RED &<&<*/ "[ Failed ]" &<&< /*RESET &<&<*/ test_case-&>testcase_name &<&< std::endl;

if (test_case-&>test_result)

{

passed_num++;

}

else

{

failed_num++;

test_result = false;

}

std::cout &<&< std::endl;

}

std::cout &<&< std::endl;

std::cout &<&< /*YELLOW &<&<*/ "[ RUN OVER ]" &<&< /*RESET &<&<*/ "Total " &<&< testcases_.size() &<&< " Unit Testing" &<&< std::endl;

std::cout &<&< /*GREEN &<&<*/ "[ PASS ]" &<&< /*RESET &<&<*/ passed_num &<&< " Units" &<&< std::endl;

std::cout &<&< /*RED &<&<*/ "[ FAIL ]" &<&< /*RESET &<&<*/ failed_num &<&< " Units" &<&< std::endl;

return test_resu<

}

enum OperatorType

{

OPERATOR_TYPE_EQ,

OPERATOR_TYPE_NE,

OPERATOR_TYPE_GT,

OPERATOR_TYPE_LT,

OPERATOR_TYPE_GE,

OPERATOR_TYPE_LE

};

template &

bool CheckNumericalData(ElemType left_value,

ElemType right_value,

const char *str_left_value,

const char *str_right_value,

const char *file_name,

const unsigned long line_num,

OperatorType operator_type)

{

bool condition;

char str_operator[5];

switch (operator_type)

{

case OPERATOR_TYPE_EQ:

if (typeid(ElemType) == typeid(double))

condition = !(fabs(left_value - right_value) &< 1e-8);

else if (typeid(ElemType) == typeid(float))

condition = !(fabs(left_value - right_value) &< 1e-6);

else

condition = !(left_value == right_value);

strcpy(str_operator, " == ");

break;

case OPERATOR_TYPE_NE:

if (typeid(ElemType) == typeid(double))

condition = !(fabs(left_value - right_value) &> 1e-8);

else if (typeid(ElemType) == typeid(float))

condition = !(fabs(left_value - right_value) &> 1e-6);

else

condition = !(left_value != right_value);

strcpy(str_operator, " != ");

break;

case OPERATOR_TYPE_GT:

condition = !(left_value &> right_value);

strcpy(str_operator, " &> ");

break;

case OPERATOR_TYPE_LT:

condition = !(left_value &< right_value);

strcpy(str_operator, " &< ");

break;

case OPERATOR_TYPE_LE:

condition = !(left_value &<= right_value);

strcpy(str_operator, " &<= ");

break;

case OPERATOR_TYPE_GE:

condition = !(left_value &>= right_value);

strcpy(str_operator, " &>= ");

break;

}

if (condition)

{

UnitTest::GetInstance()-&>current_test_case-&>test_result = 0;

std::cout &<&< file_name &<&< "(" &<&< line_num &<&< "): ";

std::cout &<&< "Error: Expect: " &<&< str_left_value &<&< str_operator &<&< str_right_value;

std::cout &<&< ", Fact: " &<&< left_value &<&< " vs " &<&< right_value &<&< std::endl;

}

return (!condition);

}

bool CheckStrData(const char *left_value,

const char *right_value,

const char *str_left_value,

const char *str_right_value,

const char *file_name,

const unsigned long line_num,

OperatorType operator_type)

{

bool condition;

char str_operator[5];

if (operator_type == OPERATOR_TYPE_EQ)

{

condition = !((strcmp(left_value, right_value) == 0));

strcpy(str_operator, " == ");

}

else if (operator_type == OPERATOR_TYPE_NE)

{

condition = !((strcmp(left_value, right_value) != 0));

strcpy(str_operator, " != ");

}

if (condition)

{

UnitTest::GetInstance()-&>current_test_case-&>test_result = 0;

std::cout &<&< file_name &<&< "(" &<&< line_num &<&< "): ";

std::cout &<&< "Error: Expect: " &<&< str_left_value &<&< str_operator &<&< str_right_value;

std::cout &<&< ", Fact: " &<&< left_value &<&< " vs " &<&< right_value &<&< std::endl;

}

return (!condition);

}

#define CHECK_NUMERICAL_DATA(left_value, right_value, operator_type)

CheckNumericalData(left_value, right_value, #left_value, #right_value, __FILE__, __LINE__, operator_type)

#define CHECK_STR_DATA(left_value, right_value, operator_type)

CheckStrData(left_value, right_value, #left_value, #right_value, __FILE__, __LINE__, operator_type)

#define EXPECT_EQ(left_value, right_value) CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_EQ)

#define EXPECT_NE(left_value, right_value) CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_NE)

#define EXPECT_GT(left_value, right_value) CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_GT)

#define EXPECT_LT(left_value, right_value) CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_LT)

#define EXPECT_GE(left_value, right_value) CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_GE)

#define EXPECT_LE(left_value, right_value) CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_LE)

#define ASSERT_EQ(left_value, right_value) if (!CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_EQ)) return;

#define ASSERT_NE(left_value, right_value) if (!CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_NE)) return;

#define ASSERT_GT(left_value, right_value) if (!CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_GT)) return;

#define ASSERT_LT(left_value, right_value) if (!CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_LT)) return;

#define ASSERT_GE(left_value, right_value) if (!CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_GE)) return;

#define ASSERT_LE(left_value, right_value) if (!CHECK_NUMERICAL_DATA(left_value, right_value, OPERATOR_TYPE_LE)) return;

#define EXPECT_TRUE(condition) CHECK_NUMERICAL_DATA(static_cast&(condition), true, OPERATOR_TYPE_EQ)

#define EXPECT_FALSE(condition) CHECK_NUMERICAL_DATA(static_cast&(condition), false, OPERATOR_TYPE_EQ)

#define ASSERT_TRUE(condition) if (!CHECK_NUMERICAL_DATA(static_cast&(condition), true, OPERATOR_TYPE_EQ)) return;

#define ASSERT_FALSE(condition) if (!CHECK_NUMERICAL_DATA(static_cast&(condition), false, OPERATOR_TYPE_EQ) return;

#define EXPECT_STREQ(left_value, right_value) CHECK_STR_DATA(left_value, right_value, OPERATOR_TYPE_EQ)

#define EXPECT_STRNE(left_value, right_value) CHECK_STR_DATA(left_value, right_value, OPERATOR_TYPE_NE)

#define ASSERT_STREQ(left_value, right_value) if (!CHECK_STR_DATA(left_value, right_value, OPERATOR_TYPE_EQ)) return;

#define ASSERT_STRNE(left_value, right_value) if (!CHECK_STR_DATA(left_value, right_value, OPERATOR_TYPE_NE)) return;

#endif

//*******source.cpp

#include "test.h"

int Add(int a, int b)

{

return a + b;

}

int Minus(int a, int b)

{

return a - b;

}

TEST(Test_PassDemo)

{

EXPECT_EQ(3, Add(1, 2));

EXPECT_EQ(0, Minus(1, 1));

}

TEST(Test_FailDemo)

{

int condition = 0;

char a[] = "acc";

char b[] = "abc";

EXPECT_STREQ(a, b);

EXPECT_TRUE(condition);

EXPECT_EQ(2, Minus(2, 2));

ASSERT_EQ(4, Add(1, 2));

EXPECT_EQ(2, Add(1, 2));

}

int main()

{

return RUN_ALL_TESTS();

}


MinUnit -- a minimal unit testing framework for C

JTN002 - MinUnit -- a minimal unit testing framework for C

所有代碼如下:

#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
#define mu_run_test(test) do { char *message = test(); tests_run++;
if (message) return message; } while (0)
extern int tests_run;


cppunit,

不過我只用過cunit, 因為部門不讓用c++

單元測試很給力,不過log也不能少


好像有個CPPUnit是專門作單元測試的,你可以了解參考一下阿


gmock

推薦一本書 《morden c++ with test driven development》


1.google test。好處是很好的「圖形」顯示。

2. boost test:boost的1.54以後新增了test庫,好處是如果已經用了boost,就不用新引入庫啦。

3. python test:用來測試一些介面挺方便。


gtest也不錯


log4c++


一般需要自己動手編寫測試程序,本文是我的一篇總結,大家可以參考:http://www.zhouzhaoxiong.com/455.html


寫個程序代碼,造自動樁函數,測試待測功能函數或者膜塊。

可用gtest測試待測函數,推薦這個因為它高端大氣上檔次,代碼少,又使用簡單,輸出很好看!

再么用log,跑程療看log。這個就沒gtest那麼好了!


推薦閱讀:

各位都是怎麼進行單元測試的?
MFC 過時了嗎?
如何用c++寫一個簡單的計算器程序?
C++在acm里的優勢相比其他語言有多大?
如何入門CDQ分治?

TAG:C |