新寫了一個簡單的單元測試框架,測試用例抽象爲TestCase對象,包含兩個接口:bool exec_case();與void report_result();
調用exec_case時,執行測試用例的單元測試函數(由具體的測試用例給出),將測試結果和相關信息記錄下來;
調用report_result時,將測試結果與相關信息輸出。
test_case.h
#ifndef __h_test_case_h__
#define __h_test_case_h__
#include <string>
#include <vector>
#include "test_common.h"
typedef bool (*TestFunc)(std::string& error_msg);
class TestCase
{
public:
TestCase(const std::string& suite_name, const std::string& case_name, TestFunc test_func);
~TestCase();
bool exec_case();
void report_result();
private:
std::string m_suite_name;
std::string m_case_name;
bool m_result;
std::string m_result_msg;
TestFunc m_test_func;
};
int exec_cases(std::vector<TestCase>& test_case_vec);
#endif
test_case.cpp
#include "test_case.h"
#include <iostream>
using namespace std;
TestCase::TestCase(const std::string& suite_name, const std::string& case_name, TestFunc test_func)
{
m_suite_name = suite_name;
m_case_name = case_name;
m_test_func = test_func;
}
TestCase::~TestCase()
{
}
bool TestCase::exec_case()
{
cout << "ExecCase:[" << m_suite_name << "]\t\t[" << m_case_name << "]" << endl;
try
{
m_result = (*m_test_func)(m_result_msg);
}
catch (exception e)
{
m_result = false;
m_result_msg = e.what();
}
return m_result;
}
void TestCase::report_result()
{
cout << endl;
cout << "TestSuite:\t" << m_suite_name << endl;
cout << "TestCase:\t" << m_case_name << endl;
cout << "TestResult:\t " << (m_result ? "Success" : "Fail") << endl;
cout << "ResultMessage:\t" << m_result_msg << endl << endl;
}
int exec_cases(std::vector<TestCase>& test_case_vec)
{
int passed_count = 0;
int failed_count = 0;
cout << endl << "-------------------Exec Cases-------------------" << endl;
for (auto it = test_case_vec.begin(); it != test_case_vec.end(); it++)
{
if (it->exec_case())
{
passed_count++;
}
else
{
failed_count++;
}
}
cout << endl << "-------------------Report Result-------------------" << endl;
for (auto it = test_case_vec.begin(); it != test_case_vec.end(); it++)
{
it->report_result();
}
cout << "Exec " << test_case_vec.size() << " cases, " << passed_count << " passed, " << failed_count << " failed." << endl;
return failed_count;
}
test_common中定義了幾個斷言宏,在測試用例中用於檢查變量值與預期是否符合。
test_common.h
#ifndef __h_test_common_h__
#define __h_test_common_h__
extern char message_buffer[4096];
void throw_exception(const char* msg);
#define ASSERT_NOT_EQUAL(value1, value2) \
if ((value1) == (value2)){ \
::memset(message_buffer, 0, sizeof(message_buffer)); \
sprintf(message_buffer, "%s(%d), (%s) == (%s)\n", __FILE__, __LINE__, #value1, #value2);\
throw_exception(message_buffer); \
}
#define ASSERT_EQUAL(value1, value2) \
if ((value1) != (value2)){ \
::memset(message_buffer, 0, sizeof(message_buffer)); \
sprintf(message_buffer, "%s(%d), (%s) != (%s)\n", __FILE__, __LINE__, #value1, #value2);\
throw_exception(message_buffer); \
}
#define ASSERT_LESS(value1, value2) \
if ((value1) >= (value2)){ \
::memset(message_buffer, 0, sizeof(message_buffer)); \
sprintf(message_buffer, "%s(%d), (%s) >= (%s)\n", __FILE__, __LINE__, #value1, #value2);\
throw_exception(message_buffer); \
}
#define ASSERT_LESS_EQUAL(value1, value2) \
if ((value1) > (value2)){ \
::memset(message_buffer, 0, sizeof(message_buffer)); \
sprintf(message_buffer, "%s(%d), (%s) > (%s)\n", __FILE__, __LINE__, #value1, #value2); \
throw_exception(message_buffer); \
}
#define ASSERT_GREAT(value1, value2) \
if ((value1) <= (value2)){ \
::memset(message_buffer, 0, sizeof(message_buffer)); \
sprintf(message_buffer, "%s(%d), (%s) <= (%s)\n", __FILE__, __LINE__, #value1, #value2);\
throw_exception(message_buffer); \
}
#define ASSERT_GREAT_EQUAL(value1, value2) \
if ((value1) < (value2)){ \
::memset(message_buffer, 0, sizeof(message_buffer)); \
sprintf(message_buffer, "%s(%d), (%s) < (%s)\n", __FILE__, __LINE__, #value1, #value2); \
throw_exception(message_buffer); \
}
#endif
test_common.cpp
#include "test_common.h"
#include <exception>
char message_buffer[4096];
void throw_exception(const char* msg)
{
std::exception e(msg);
throw e;
}
test_login中寫了一個簡單的測試用例
test_login.h
#ifndef __h_test_login_h__
#define __h_test_login_h__
#include "test_case.h"
namespace test_login
{
bool test_login(std::string& error_msg)
{
int i = 0;
ASSERT_GREAT_EQUAL(i, 0);
return true;
}
struct TestLogin : public TestCase
{
public:
TestLogin(const std::string& suite_name = "MDLL_SWSSL_Step_test", const std::string& case_name = "test_login", TestFunc test_func = test_login)
:TestCase(suite_name, case_name, test_func)
{
}
};
}
#endif
測試入口,main函數所在
test.cpp
#include "test_case.h"
#include "test_login/test_login.h"
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<TestCase> test_case_vec;
test_case_vec.push_back(test_login::TestLogin());
return exec_cases(test_case_vec);
}