C++自制测试管理类

// 个人自制的C++测试管理类

// 代码(2018年版)结构如下:

1 TestBase: 测试对象的基类:

    针对具体的测试对象,只要重载TEST_MAIN接口即可。

2 TestManager:测试对象的管理类:

    实现对测试对象的添加,运行和删除操作。

    针对具体的测试对象,实际上仅需要使用Add_<***>()即可。

3 一个调用示例:

// 具体代码如下:

TestBase类,仅一个头文件hpp,没有其他文件。

// TestBase.hpp
// 测试单元对象的基类
// Mylaf 
// 2018-01-18 2032
// 

#ifndef _ME_TESTBASE_HEADER_
#define _ME_TESTBASE_HEADER_

#if (defined _WIN32 || defined WINCE || defined __CYGWIN__)
	// Windows
#	include <io.h>
#	include <direct.h>

//#	if _DEBUG
//#		pragma comment(lib, "mylaf.271603091qqd.lib")
//#	else //!_DEBUG
//#		pragma comment(lib, "mylaf.271603091qq.lib")
//#	endif //_DEBUG

#	pragma warning(disable:4996)

//int _mkdir(const char *dirname);
#	define __mkdir(path,mode)   _mkdir((path))
//int _access(const char *path, int mode);
#	define __access  _access 

#define LIB_EXPORT
#if defined LIB_EXPORT
#define ME_C_API __declspec(dllexport)
#define ME_F_API extern "C" __declspec(dllexport)
#else // !LIB_EXPORT
#define ME_C_API __declspec(dllimport)
#define ME_F_API extern "C" __declspec(dllimport)
#endif // LIB_EXPORT

#elif (defined __GNUC__ && __GNUC__ >= 4)
#	include <sys/stat.h> 
#	include <sys/types.h>
#	include <unistd.h>

//int mkdir(const char *path, mode_t mode);
#	define __mkdir(path,mode)  mkdir((path),(mode))
//int access(const char *pathname, int mode)
#	define __access access

#if defined LIB_EXPORT
#define ME_C_API  
#define ME_F_API  
#else // !LIB_EXPORT
#define ME_C_API  
#define ME_F_API 
#endif // LIB_EXPORT

#endif //

#include <iostream>
#include <fstream>

class ME_C_API TestBase {
public:
	TestBase() {}
	virtual ~TestBase() {}

public:
	// @name:TEST_MAIN
	// @brief:本测试文件的入口
	// @note:请在此函数体内添加您的单元测试
	// //@param[i]:argc 参数个数
	// //@param[i]:argv 参数列表
	// @warning:请不要修改此函数声明
	// 
	virtual int TEST_MAIN(/*int argc, char* argv[]*/) {
		std::cout << std::endl << "------------------------------";
		std::cout << std::endl << __FUNCTION__ << " [" << __FILE__ << "] >>>" << std::endl;

		// TODO: 请在下面的位置添加您的单元测试调用
		// 调用多文件测试
		//MultiTest();
		// 调用单文件测试
		//SingleTest();
		// 调用单元测试0001
		Test0001();
		// 调用其他测试
		// ...


		std::cout << std::endl << "<<<" << __FUNCTION__ << " [" << __FILE__ << "] ";
		std::cout << std::endl << "------------------------------" << std::endl;
		return 0;
	}

private:
	// 多个文件测试
	// path 是 文件夹image和文件 image.namelist.txt的父目录
	int MultiTest(const char* path) {
		if (path == NULL) {
			std::cout << "PATH is NULL." << std::endl;
			return -1;
		}

		// 路径是否存在
		if (__access(path, 0) != 0) {
			std::cout << "PATH NOT found." << std::endl;
			return -2;
		}

		// 路径下面是否存在文件夹image和文件 image.namelist.txt
		char sz[260] = { 0 };
		sprintf(sz, "%s/image", path);
		if (__access(path, 0) != 0) {
			std::cout << "PATH/image NOT found." << std::endl;
			return -3;
		}
		sprintf(sz, "%s/image.namelist.txt", path);
		if (__access(path, 0) != 0) {
			std::cout << "PATH/image.namelist.txt NOT found." << std::endl;
			return -4;
		}

		// 读取image.namelist.txt内容
		std::ifstream fin(sz, std::ios::binary | std::ios::in);
		if (fin.fail()) {
			std::cout << "Read file is failed!" << std::endl;
			return -5;
		}

		char file[260];
		while (!fin.eof()) {
			memset(sz, 0, 260);
			fin.getline(sz, 256, '\n');

			// 跳过注释行
			if (sz[0] == '#') {
				continue;
			}

			// 处理Windows系统的\r\n
			if (sz[strlen(sz) - 1] == '\r') {
				sz[strlen(sz) - 1] = 0;
			}

			// 获取完整路径
			memset(file, 0, 260);
			sprintf(file, "%s/image/%s", path, sz);

			// 检测完整路径是否存在
			if (__access(file, 0) != 0) {
				std::cout << file << " NOT found." << std::endl;
				continue;
			}

			// TODO:调用单元测试并传递所需的参数
			Test0001();
		}
		
		// 关闭文件
		fin.close();

		return 0;
	}

	// 单个文件测试
	int SingleTest(const char* file) {
		if (file == NULL) {
			std::cout << "FILE is NULL." << std::endl;
			return -1;
		}

		// 判断路径是否存在
		if (__access(file, 0) != 0) {
			std::cout << "PATH NOT found." << std::endl;
			return -2;
		}
		
		// TODO:调用单元测试并传递所需的参数
		Test0001();

		return 0;
	}

private:
	// 单元测试001
	virtual void Test0001() {
		std::cout << __FUNCTION__ << ">>>" << std::endl;
	}
	// 自行定义其他单元测试:格式无限。
	// 记得自行添加到 TEST_MAIN 或 MultiTest 或 SingleTest。
};

#endif // _ME_TESTBASE_HEADER_

TestManager类:TestManager.h和TestManager.cpp两个文件。

// TestManager.h
// 测试单元对象管理类
// Mylaf
// 2018-01-18 2036
// 
// 使用示例:
//	获取管理器的全局实例
//	TestManager* mgr = TestManager::getInstance();
//
//	// TODO: 请在此处添加您的单元测试对象
//	mgr->Add_<TestBase>();
//
//	// 运行
//	mgr->Run();
//
//	// 释放资源
//	mgr->Delete();
//

#ifndef _ME_TESTMANAGER_HEADER_
#define _ME_TESTMANAGER_HEADER_

#include "TestBase.hpp"

#include <vector>
#include <type_traits>
#include <mutex>

class ME_C_API TestManager {
private:
	static TestManager* instance; 
	std::vector<TestBase*> vec_testptr;
	std::mutex mtx;

private:
	TestManager() {}
	virtual ~TestManager() { Delete(-1); }

public:
	// 单例模式:获取全局的实例对象指针
	static TestManager* getInstance();

public:
	// 添加测试单元对象类:必须继承于TestBase,否则无效。
	// 返回位置(位置可用于Delete)
	template<typename _Ty>
	int Add_(void);

	// 运行测试
	virtual void Run(void);

	// 删除指定位置的测试单元
	// 当pos >= 0时,只删除pos位置上的测试单元,如果位置
	virtual void  Delete(int pos = -1);
};

// 添加测试单元对象类:必须继承于TestBase,否则无效。
// 返回位置(位置可用于Delete)

template<typename _Ty>
inline int TestManager::Add_(void) {
	mtx.lock();

	int pos = -1;
	if (std::is_same<TestBase, _Ty>::value
		|| std::is_base_of<TestBase, _Ty>::value) {
		//
		TestBase* ptr = new _Ty();
		if (ptr != nullptr) {
			// 查找存放的位置
			pos = vec_testptr.size() - 1;
			for (; pos > -1; --pos) {
				if (vec_testptr[pos] == nullptr) {
					// 修改
					vec_testptr[pos] = ptr;
					break;
				}
			}
			// 
			if (pos < 0) {
				// 如果当前vec里面没有空位,则追加到vec尾巴
				pos = vec_testptr.size();
				vec_testptr.push_back(ptr);
			}
		}
	}
	//std::cout << "Add: is_base_of(TestBase,***)" << std::endl;
	mtx.unlock();

	return pos;
}

#endif // _ME_TESTMANAGER_HEADER_
// TestManager.cpp
// 测试单元对象管理类
// Mylaf
// 2018-01-18 2036
// 

#include "TestManager.h"

TestManager* TestManager::instance = nullptr;

// 单例模式:获取全局的实例对象指针
TestManager * TestManager::getInstance() {
	if (instance == nullptr) {
		instance = new TestManager();
	}
	return instance;
}

// 运行测试

void TestManager::Run(void) {
	mtx.lock();
	for (int i = 0; i < vec_testptr.size(); ++i)
	{
		if (vec_testptr[i] == nullptr) {
			continue;
		}

		// 调用各自的测试入口
		vec_testptr[i]->TEST_MAIN();
	}
	mtx.unlock();
}

// 删除指定位置的测试单元
// 当pos >= 0时,只删除pos位置上的测试单元,如果位置

void TestManager::Delete(int pos) {
	mtx.lock();
	if (pos < 0) {
		// 删除从abs(pos)-1位置开始的所有测试单元
		for (int i = -pos - 1; i < vec_testptr.size(); ++i) {
			delete vec_testptr[i];
			vec_testptr[i] = nullptr;
		}
	}
	else {
		// 删除指定位置的所有测试单元
		if (pos > -1 && pos < vec_testptr.size()) {
			delete vec_testptr[pos];
			vec_testptr[pos] = nullptr;
		}
	}
	mtx.unlock();
}

调用方法实例:仅一个文件main.cpp。

// main.cpp
// 测试管理调用示例
// Mylaf
// 2018-01-18 2040
//

#include "TestManager.h"

int main() {
	//
	TestManager* mgr = TestManager::getInstance();

	// 添加测试类TestBase
	mgr->Add_<TestBase>();

	// TODO:在此处添加您的测试类
	// 添加测试类的示例如上【添加测试类TestBase】

	// 运行测试类
	mgr->Run();

	// 删除所有测试类
	mgr->Delete();

	//
	return 0;
}

// 运行效果

 

// Mylaf

// 厦门

// 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值