1. 目的
日常用 GoogleTest 作为单元测试框架, 熟悉它的基本用法。想在练手的 C++ 工程中也写点单元测试, 想要一个比 GoogleTest 更轻量的测试框架: 只支持 >= C++11, header-only, 不带正则匹配, 输出有颜色区分等。 对于 C++ 不太熟悉, 那就尝试从头写一个来熟悉 C++ 吧!
2. 思路
颜色高亮输出: ascii escape chars 即可。
检查表达式取值为 true 还是 false, 分别输出: 参照 assert 宏的实现,自行重新定义。
注册单元测试函数:在 main() 函数运行前要注册每个单元测试函数, 每次注册时压栈一个函数到容器,容器放在全局唯一的一个类对象里(也就是Singleton)。容器元素类型是 std::function.
一次性运行所有测试函数:获取Singleton后遍历容器里每个对象并调用执行。
3. 实现
最终完整实现代码如下:
#include <stdlib.h>
#include <functional>
#include <string>
#include <map>
#include <vector>
#if __ANDROID_API__ >= 8
#include <android/log.h>
#define MY_LOGE(...) \
do { \
fprintf(stderr, ##__VA_ARGS__); \
__android_log_print(ANDROID_LOG_WARN, "my", ##__VA_ARGS__); \
} while (0)
#else
#include <stdio.h>
#define MY_LOGE(...) \
do { \
fprintf(stderr, ##__VA_ARGS__); \
} while (0)
#endif
#define MY_ESCAPE_COLOR_RED "\x1b[31m"
#define MY_ESCAPE_COLOR_GREEN "\x1b[32m"
#define MY_ESCAPE_COLOR_YELLOW "\x1b[33m"
#define MY_ESCAPE_COLOR_END "\x1b[0m"
void my_true_fail(const char* assertion, const char* filename, unsigned int linenumber, const char* function)
{
MY_LOGE("%s%s:%d: Failure%s\n", MY_ESCAPE_COLOR_RED, filename, linenumber, MY_ESCAPE_COLOR_END);
MY_LOGE("Value of: %s\n Actual: false\nExpected: true\n", assertion);
}
void my_true_success(const char* assertion, const char* filename, unsigned int linenumber, const char* function)
{
MY_LOGE("%s:%d %s(): Assertion %s`%s' ok%s.\n", filename, linenumber, function, MY_ESCAPE_COLOR_GREEN, assertion, MY_ESCAPE_COLOR_END);
}
void my_equal_fail(const char* expected, const char* actual, const char* filename, unsigned int linenumber, const char* function)
{
MY_LOGE("%s%s:%d: Failure%s\n", MY_ESCAPE_COLOR_RED, filename, linenumber, MY_ESCAPE_COLOR_END);
MY_LOGE("Expected: %s\n Actual: %s\nExpected: true\n", expected, actual);
}
void my_equal_success(const char* expected, const char* actual, const char* filename, unsigned int linenumber, const char* function)
{
MY_LOGE("%s:%d %s(): %s`MY_EXPECTED_EQ(%s, %s)' ok%s.\n", filename, linenumber, function, MY_ESCAPE_COLOR_GREEN, expected, actual, MY_ESCAPE_COLOR_END);
}
#define MY_EXPECT_TRUE(expr) \
(static_cast<bool>(expr) \
? my_true_success(#expr, __FILE__, __LINE__, __FUNCTION__) \
: my_true_fail(#expr, __FILE__, __LINE__, __FUNCTION__))
#define MY_ASSERT_TRUE(expr) \
if (static_cast<bool>(expr)) { \
my_true_success(#expr, __FILE__, __LINE__, __FUNCTION__); \
} \
else { \
my_true_fail(#expr, __FILE__, __LINE__, __FUNCTION__); \
return; \
}
#define MY_EXPECT_EQ(expected, actual) \
(static_cast<bool>(expected == actual) \
? my_equal_success(#expected, #actual, __FILE__, __LINE__, __FUNCTION__) \
: my_equal_fail(#expected, #actual, __FILE__, __LINE__, __FUNCTION__));
#define MY_ASSERT_EQ(expected, actual) \
if (static_cast<bool>(expected == actual)) { \
my_equal_success(#expected, #actual, __FILE__, __LINE__, __FUNCTION__); \
} \
else { \
my_equal_fail(#expected, #actual, __FILE__, __LINE__, __FUNCTION__); \
return; \
}
class TestEntity
{
private:
TestEntity() { };
~TestEntity() { };
public:
TestEntity(const TestEntity& other) = delete;
TestEntity operator=(const TestEntity& other) = delete;
static TestEntity& get_instance()
{
static TestEntity entity;
return entity;
}
int add(std::function<void()> f)
{
test_funcs.push_back(f);
return 0;
}
int run_all_test_functions()
{
for (auto f : test_funcs)
{
f();
}
return 0;
}
private:
std::vector<std::function<void()>> test_funcs;
};
#define MY_TEST(name) \
void my_test_##name(); \
int my_test_mark_##name = TestEntity::get_instance().add(my_test_##name); \
void my_test_##name()
#define MY_UNUSED(x) (void)(x)
#define MY_RUN_ALL_TESTS() \
int my_test_invoker = TestEntity::get_instance().run_all_test_functions(); \
MY_UNUSED(my_test_invoker)
调用代码举例:
// Returns the factorial of n
int Factorial(int n)
{
if (n == 1 || n == 2) return n;
return Factorial(n - 1) + Factorial(n - 2);
}
MY_TEST(equal)
{
int p = 3;
MY_EXPECT_TRUE(p == 3);
}
MY_TEST(factorial)
{
// MY_EXPECT_EQ(Factorial(1), 1);
// MY_EXPECT_EQ(Factorial(2), 2);
// MY_EXPECT_EQ(Factorial(3), 6);
// MY_EXPECT_EQ(Factorial(8), 40320);
// MY_ASSERT_EQ(Factorial(1), 1);
// MY_ASSERT_EQ(Factorial(2), 2);
// MY_ASSERT_EQ(Factorial(3), 6);
// MY_ASSERT_EQ(Factorial(8), 40320);
// MY_ASSERT_TRUE(Factorial(1) == 1);
// MY_ASSERT_TRUE(Factorial(2) == 2);
// MY_ASSERT_TRUE(Factorial(3) == 6);
// MY_ASSERT_TRUE(Factorial(8) == 40320);
MY_EXPECT_TRUE(Factorial(1) == 1);
MY_EXPECT_TRUE(Factorial(2) == 2);
MY_EXPECT_TRUE(Factorial(3) == 6);
MY_EXPECT_TRUE(Factorial(8) == 40320);
}
int main()
{
MY_RUN_ALL_TESTS();
return 0;
}
运行结果:
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理