国家重点建设裤网站,建个静态网站,网页小游戏源码,seo搜索引擎优化介绍GoogleTest
googletest: GoogleTest - Google Testing and Mocking Framework
googletest 是一个由 Google 的测试技术团队开发的测试框架#xff0c;它考虑到了谷歌的特定需求和限制。无论你使用的是 Linux、Windows 还是 Mac#xff0c;只要你编写 C 代码#xff0c;goo…GoogleTest
googletest: GoogleTest - Google Testing and Mocking Framework
googletest 是一个由 Google 的测试技术团队开发的测试框架它考虑到了谷歌的特定需求和限制。无论你使用的是 Linux、Windows 还是 Mac只要你编写 C 代码googletest 都可以帮到你。它支持任何类型的测试不只是单元测试。 独立的且可重复的googletest 通过在不同的对象上运行每个测试用例来隔离测试。当测试失败时允许你单独运行它以便快速调试 可移植的且可复用的googletest 适用于不同的操作系统不同的编译器 失败时提供尽可能多的关于故障的信息googletest 不会在第一个测试失败时停止。相反它仅停止当前的测试并继续运行下一个 得到良好的组织并反映测试代码的结构googletest 将相关的测试分组为测试套件它们可以共享数据和子例程 测试框架将精力集中在测试内容上googletest 自动追踪所有定义的测试且无需用户以运行它们的顺序迭代它们 快通过 googletest可以跨测试用例复用共享资源且只支出一次 set-up/tear-down 的开销不使测试相互依赖。 任何可被送给 ostream 的都可以被送进断言的宏。 编译
gtest 提供了两种编译方式 bazel 和 cmake以 cmake 为例
mkdir build cd build
cmake ..
# 只需要包含头文件 gtest.h或者gmock.h断言
断言是 gtest 核心组成所有的测试用例最终都是以断言实现的。 ASSERT 系列的断言如果失败则会产生一个严重错误并导致当前作用范围的测试用例中断 EXPECT 不会产生任何错误测试用例依旧可以继续执行。
true / false 条件测试
致命非致命验证ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition: trueASSERT_FALSE(condition);EXPECT_FALSE(condition);condition: false 失败时ASSERT_* 产生一个致命错误并从当前函数退出EXPECT_* 则产生一个非致命错误并允许函数继续运行。 二元比较
致命断言非致命断言验证ASSERT_EQ(val1, val2);EXPECT_EQ(val1, val2);val1 val2ASSERT_NE(val1, val2);EXPECT_NE(val1, val2);val1 ! val2ASSERT_LT(val1, val2);EXPECT_LT(val1, val2);val1 val2ASSERT_LE(val1, val2);EXPECT_LE(val1, val2);val1 val2ASSERT_GT(val1, val2);EXPECT_GT(val1, val2);val1 val2ASSERT_GE(val1, val2);EXPECT_GE(val1, val2);val1 val2 比较 C 字符串ASSERT_EQ 测试它们是否位于相同内存位置而不是是否具有相同的值。因此比较 C 字符串的值使用 ASSERT_STREQ() 当执行指针比较时使用 *_EQ(ptr, nullptr) 和 *_NE(ptr, nullptr) 而不是 *_EQ(ptr, NULL) 和 *_NE(ptr, NULL)。 字符串比较
致命断言非致命断言验证ASSERT_STREQ(str1, str2);EXPECT_STREQ(str1, str2);具有相同内容ASSERT_STRNE(str1, str2);EXPECT_STRNE(str1, str2);具有不同内容ASSERT_STRCASEEQ(str1, str2);EXPECT_STRCASEEQ(str1, str2);相同内容忽略大小写ASSERT_STRCASENE(str1, str2);EXPECT_STRCASENE(str1, str2);不同内容忽略大小写 如果宽字符串wchar_t* Windows 上 UNICODE 模式的 TCHAR*或 std::wstring被送进断言它将在打印时被转换为 UTF-8。 断言扩展
SUCCEED() : 产生一个成功标识只代表某一个步躁成功
FAIL() : 产生一个严重错误相当于一个 ASSERT 宏失败
ASSERT_THROW(expre,type) : 断言表达式 expre 会抛出一个 type 类型异常
ASSERTANY THROW(expre) : 断言表达式 expre 会抛出一个任意类型异常
ASSERT_NO_THROW(expre) : 断言表达式 expre 不会抛出任何异常。
测试 TEST 使用 TEST() 宏定义并命名一个测试函数没有返回值的宏函数 解析命令行中的 GoogleTest 参数它允许用户通过多样的命令行参数来控制测试程序的行为即定制命令行参数的行为testing::InitGoogleTest(argc, argv); 搜索不同的 Test Case 和不同的源文件中所有已经存在的测试案例然后运行它们成功时返回 1否则返回 0return RUN_ALL_TESTS();。
// 1. TestSuiteName 测试套件名
// 2. TestName 测试用例名
/// 名称不该包含下划线
TEST(FactorialTest, HandlesZeroInput) {EXPECT_EQ(Factorial(0), 1);
}
TEST(FactorialTest, HandlesPositiveInput) {EXPECT_NE(Factorial(1), 1);
} int main(int argc, char** argv) {testing::InitGoogleTest(argc, argv);return RUN_ALL_TESTS();
}Google C Style Guide 函数和类命名规则
全局事件
#include gtest/gtest.h
class TestFA2 : public testing::Environment {
public:void SetUp() override {std::cout SetUp std::endl;}void TearDown() override {std::cout TearDown std::endl;}
};
TEST(TestFA21, globalEnv) {EXPECT_EQ(3, 4) int compare;
}
int main(int argc, char** argv) {testing::InitGoogleTest(argc, argv);testing::Environment* env new TestFA2();testing::AddGlobalTestEnvironment(env);int ret 0;ret RUN_ALL_TESTS();return ret;
}测试夹具 TEST_F 允许你为多个不同的测试复用相同的数据对象配置。 googletest 不 为多个测试复用相同的测试夹具。
成员函数
虚函数
virtual void SetUp()类似于构造函数在 TEST_F 之前运行virtual void TearDown()类似于析构函数在 TEST_F 之后运行。
静态函数
static void SetUpTestSuite()在第一个 TEST 之前运行static void TearDownTestSuite()在最后一个 TEST 之后运行。
全局事件 继承 testing::Environment virtual void SetUp()在所有用例之前运行virtual void TearDown()在所有用例之后运行。
创建 创建一个公有继承自 ::testing::Test 的类进行 protected 类内部声明 编写一个默认的构造函数或 SetUp() 函数为每个 test 准备对象 编写一个析构函数或 TearDown() 函数释放 SetUp() 中分配的资源 完善类资源信息使用 TEST_F 宏第一个参数填写新建夹具类名称。 由于 C 语法不允许在构造/析构函数中调用虚函数 SetUp/TearDown建议优先使用构造/析构函数完成数据的初始化。 使用
使用 TEST_F(类名, 测试夹具名称)
// TestFixtureName 测试夹具类名_Ffixture
TEST_F(TestFixtureName, TestName) {... test body ...
}通过 TEST_F() 定义的每个测试googletest 将在运行时自动创建一个 全新的 测试夹具立即通过 SetUp() 初始化它运行测试最后调用 TearDown() 清理资源然后删除测试夹具。
具体类定义
template typename E // E is the element type.
class Queue {
public:Queue();void Enqueue(const E element);E* Dequeue(); // Returns NULL if the queue is empty.size_t size() const;...
};夹具类定义
#include gtest/gtest.h
class TestFA : public ::testing::Test {
public:TestFA() {}~TestFA() {}protected:void SetUp() override {std::cout Reference count: deq.use_count() std::endl;auto p deq.get();auto pxin *p;std::deque int a(5, -1);std::cout 1. size: pxin.size() std::endl;pxin.swap(a);std::cout 2. size: pxin.size() std::endl;}void TearDown() override {deq.reset();deq nullptr;}public:std::shared_ptr std::deque int deq std::make_shared std::deque int ();
};测试定义
测试案例都来自同一个测试夹具不同的测试案例拥有相互独立的个体独占数据不会相互影响。
TEST_F(TestFA, isEmptyOnB) {EXPECT_GE(deq.use_count(), 1);if (deq.use_count() ! 0) {deq.reset();}
}
TEST_F(TestFA, isEmptyOnBIndependence) {EXPECT_GE(deq.use_count(), 1);
}测试调用
定义测试后通过 RUN_ALL_TESTS() 运行它们如果所有测试都成功,返回 0否则返回 1。
调用 RUN_ALL_TESTS() 宏时 保存所有 googletest 标记的状态 为第一个测试创建一个测试夹具对象 通过 SetUp() 初始化 在测试夹具对象上运行测试 通过 TearDown() 清理测试夹具 删除夹具恢复所有的 googletest 标记的状态 为下一个测试重复上述步骤。
#include gtest/gtest.h
int main(int argc, char** argv) {// 解析 googletest 标记的命令行参数并移除所有已识别的标记testing::InitGoogleTest(argc, argv);return RUN_ALL_TESTS();
}调用 RUN_ALL_TESTS() 一次多次调用将产生冲突。 接口测试 Gmock
Google C单元测试框架GoogleTest—Google Mock简介–概念及基础语法 - 超超boy - 博客园
使用步骤
创建抽象类
创建抽象接口函数
class B {
public:virtual const int sub(int s1, const int s2) const 0;
};创建 Mock 类继承
类返回作用域、参数作用域等都需要进行描述
#include gmock/gmock.h
class MockB : public B {
public:MOCK_METHOD(const int, sub, ( int, const int ), (const, override));
};Mock 测试
EXPECT_CALL(mock_object, method(matchers)) // 对象、匹配调用函数 .Times(cardinality) // 调用次数 .WillOnce(action) // 被调用一次时的行为 .WillRepeatedly(action); // 重复调用
#include B.h
#include gtest/gtest.h
MockB b;
TEST(mock_sub, actionBSub) {EXPECT_CALL(b, sub).Times(::testing::AtLeast(3)) // 3次需要3个WillOnce.WillOnce(::testing::Return(1)).WillOnce(::testing::Return(2)).WillOnce(::testing::Return(34));std::cout b.sub(2, 1) std::endl;std::cout b.sub(3, 1) std::endl;std::cout b.sub(55, 44) std::endl;std::cout b.sub(34, 0) std::endl; // 默认返回 0
} // 参数匹配器
TEST(mock_sub, expectCall) {EXPECT_CALL(b, sub(123, 123)).WillRepeatedly(Return(246));std::cout b.sub(123, 1234) std::endl; // 默认 0std::cout b.sub(123, 123) std::endl; // 符合246测试用例失效std::cout b.sub(123, 123) std::endl; // 默认 0EXPECT_CALL(b, sub(Gt(123), _)).WillOnce(Return(1234)); // 大于 123和任意数值std::cout b.sub(124, 123) std::endl; // 符合-99std::cout b.sub(123, 2) std::endl; // 0
} // 顺序适配器
TEST(mock_multi_sub, callInSequence) {Sequence s1;EXPECT_CALL(b, multi).InSequence(s1).WillOnce(Return(222)); // 先EXPECT_CALL(b, sub).InSequence(s1).WillOnce(Return(333)); // 后std::cout b.sub(124, 123) std::endl; // 不符。为 0std::cout b.multi(123, 2) std::endl; // 先222std::cout b.sub(124, 123) std::endl; // 后333
}EXPECT_CALL
Times 至少调用次数小于则默认回调如默认 int 返回 0WillRepeatedly 重复调用类似默认调用::testing::Gt(a) 函数参数匹配设置匹配器如当大于 a 时则匹配调用InSequence 指定顺序适配器 Sequence 顺序调用成员函数
示例
示例1web 请求
std::string chat_room::log() {std::string* response;this-requester-execute(request,response); // web访问结果存在response指针中return *response;
} class http_request {
public:virtual ~http_request() {}virtual bool execute(std::string request, std::string* response) 0;
};
class mock_http_request : public http_request {
public:MOCK_METHOD(bool, execute, (std::string request, std::string* response),(override));
}; TEST(ChatRoomTest, log) {testing::NiceMock mock_message_dao mock_dao; // 在下一部分会提到mock_message_daomock_http_request mock_requester; // Mock对象std::string response response; // 期待调用函数的第二个参数将指向这个string对象EXPECT_CALL(mock_requester, execute).WillRepeatedly( // 每次调用都会WillRepeatedly执行testing::DoAll( // 每次执行包含多个行为testing::SetArgPointee 1 (response), // 将传入参数指针变量response指向responsetesting::Return(true))); // 返回值为truechat_room cr chat_room(mock_dao, mock_requester); // 将mock对象通过chat_room的constructor注入EXPECT_EQ(cr.log(), response); // 调用和Google Test断言
}示例2数据库访问
void chat_room::join(chat_participant_ptr participant) {participants_.insert(participant);std::vector std::string recent_msg_strs this-dao-get_messages(); // 从数据库中获取历史消息for (std::string recent_msg_str : recent_msg_strs) {// 将每一个消息发送给该聊天参与者auto msg chat_message();msg.set_body_string(recent_msg_str);participant-deliver(msg);}
} class message_dao {
public:virtual ~message_dao() {}virtual bool add_message(std::string m) 0;virtual std::vector std::string get_messages() 0;
}; class mock_message_dao : public message_dao {
public:MOCK_METHOD(bool, add_message, (std::string m), (override));MOCK_METHOD(std::vector std::string , get_messages, (), (override));
};
EST(ChatRoomTest, join) {mock_message_dao mock_dao; // 创建mock对象需要注入chat_roomhttp_request_impl requester; // 创建web访问对象也需要注入chat_roomauto mock_p1 std::make_shared mock_chat_participant ();// 创建participant的mock指针EXPECT_CALL(mock_dao, get_messages).WillOnce(testing::Return(std::vector std::string { test_1, test_2, test_3 }));// 指定get_messages调用的返回值EXPECT_CALL(*mock_p1, deliver).Times(3);// 指定deliver调用的次数chat_room cr chat_room(mock_dao, requester);// 创建chat_room对象注入dao和requestercr.join(mock_p1); // 调用
}注意 测试套件名称、测试夹具名称、测试名称中不应该出现下划线 TEST(TestSuiteName, TestName)生成名为TestSuiteName_TestName_Test 的类 Uniteresting mock function call 警告 没有相应匹配的EXCEPT_CALLGoogle Mock 会生成这个警告使用 NiceMock 进行 mock 类对象实例化 Mock 一般用于虚函数通过 TMock 来 Mock 非虚函数 单元测试文件可以放在根目录下面专用的 tests 文件夹下