C++簡單單元測試類

參考自LEVELDB中的單元測試類

頭文件(testharness.h):

#ifndef TEST_HARNESS_H_
#define TEST_HARNESS_H_

#include <sstream>

namespace simpleut {
	namespace test {
		//執行所有的單元測試
		extern int RunAllTest();

		class Tester {
		private:
			bool ok_;
			const char* fname_;
			int line_;
			std::stringstream ss_;

		public:
			Tester(const char* f, int l):
			  ok_(true), fname_(f), line_(l) {}

			~Tester() {
				if (!ok_) {
					fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str());
					exit(1);
				}
			}

			Tester& Is(bool b, const char* msg) {
				if (!b) {
					ss_ << " Assertion failed " << msg;
					ok_ = false;
				}
				return *this;
			}

#define BINARY_OP(name, op)									\
	template<class X, class Y>								\
	Tester& name(const X& x, const Y& y) {					\
		if (!(x op y)) {									\
			ss_ << " failed: " << x << (" " #op " ") << y;	\
			ok_ = false;									\
		};													\
		return *this;										\
	}

			BINARY_OP(IsEq, ==)
			BINARY_OP(IsNe, !=)
			BINARY_OP(IsGe, >=)
			BINARY_OP(IsGt, >)
			BINARY_OP(IsLe, <=)
			BINARY_OP(IsLt, <)
#undef BINARY_OP

			template<class V>
			Tester& operator<<(const V& value) {
				ss_ << " " << value;
				return *this;
			}
		}; //Tester

#define ASSERT_TRUE(c)  ::simpleut::test::Tester(__FILE__, __LINE__).Is((c), #c)
#define ASSERT_EQ(a, b) ::simpleut::test::Tester(__FILE__, __LINE__).IsEq((a), (b))
#define ASSERT_NE(a, b) ::simpleut::test::Tester(__FILE__, __LINE__).IsNe((a), (b))
#define ASSERT_GE(a, b) ::simpleut::test::Tester(__FILE__, __LINE__).IsGe((a), (b))
#define ASSERT_GT(a, b) ::simpleut::test::Tester(__FILE__, __LINE__).IsGt((a), (b))
#define ASSERT_LE(a, b) ::simpleut::test::Tester(__FILE__, __LINE__).IsLe((a), (b))
#define ASSERT_LT(a, b) ::simpleut::test::Tester(__FILE__, __LINE__).IsLt((a), (b))

#define TCONCAT(a, b) TCONCAT1(a, b)
#define TCONCAT1(a, b) a##b

#define TEST(base, name)						\
	class TCONCAT(_Test_, name) : public base {	\
	public:										\
		void _Run();							\
		static void _RunIt() {					\
			TCONCAT(_Test_, name) t;			\
			t._Run();							\
		}										\
	};											\
	bool TCONCAT(_Test_ignored_, name) =			\
		::simpleut::test::RegisterTest(#base, #name, &TCONCAT(_Test_, name)::_RunIt); \
	void TCONCAT(_Test_, name)::_Run()

		extern bool RegisterTest(const char* base, const char* name, void (*func)());
	}
}

#endif //TEST_HARNESS_H_

CPP文件(testharness.cpp):

#include "testharness.h"

#include <vector>

namespace simpleut {
	namespace test {
		namespace {
			struct Test {
				const char* base;
				const char* name;
				void (*func)();
			};

			std::vector<Test>* tests;
		}

		bool RegisterTest(const char* base, const char* name, void (*func)()) {
			if (tests == NULL) {
				tests = new std::vector<Test>;
			}

			Test t;
			t.base = base;
			t.name = name;
			t.func = func;
			tests->push_back(t);

			return true;
		}

		int RunAllTest() {
			int num = 0;
			if (tests != NULL) {
				for (size_t i=0; i<tests->size(); ++i) {
					const Test& t = (*tests)[i];

					fprintf(stderr, "++++ Test %s.%s\n", t.base, t.name);
					(*t.func)();
					num++;
				}

				fprintf(stderr, "==== PASSED %d tests\n", num);
			}

			return 0;
		}
	}
}

使用代碼:

#include "testharness.h"

int add(int a, int b) {
	return a + b;
}

class SimpleTest {};

TEST(SimpleTest, AddTest) {
	int result = add(2, 3);
	ASSERT_EQ(result, 5);
}

int main(int argc, char* argv[]) {
	::simpleut::test::RunAllTest();
	
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章