FakeIt FakeIt是一个单元测试工具,类比gmock, 但是比gmock更modern和轻量,因为它支持c++11和header-only
使用方法 FakeIt和gmock都提供Mock和调用计数功能,Mock通常用于接口类,用来定义并实例化接口类对象。gmock和FakeIt都能对调用参数进行校验,但FakeIt的Verify函数还提供在校验失败时打印参数值,这是gmock不具备的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 struct IAppManager {   // inotify calls when new event   virtual void notify_add_event(EventType event_type,                                 const std::string& filepath) = 0;   virtual void notify_rename_event(EventType event_type,                                    const std::string& filepath,                                    const std::string& filepath_new) = 0;   virtual ~IAppManager() = default; }; TEST_CASE("Test Inotify") {   Mock<IAppManager> appmanager_mock;   Fake(Dtor(appmanager_mock));   Fake(Method(appmanager_mock, notify_add_event));   Fake(Method(appmanager_mock, notify_rename_event));   auto& app_manager = appmanager_mock.get();   SECTION("test add") {     std::thread t1([&app_manager](){       app_manager.notify_add_event(EventType::File, "filename");       app_manager.notify_add_event(EventType::File, "filename");       app_manager.notify_add_event(EventType::File, "filename");     });     t1.join();     Verify(Method(appmanager_mock, notify_add_event)).Exactly(2);   } } 
 
这里没有对调用参数校验,而仅对调用次数验证,可以预见,结果失败,因为调用了3次。
问题 上面的测试用例会失败,因为次数不匹配。而这时FakeIt会打印所有调用的参数值,但参数由于是个引用,而且引用在线程退出时被释放,打印一个无效引用导致会抛异常
1 2 due to a fatal error condition:                                                                    SIGSEGV - Segmentation violation signal 
 
解决办法 对于本测试而言,解决办法就是将传参所引用的对象duration改大,如全局变量或者static,或者在线程外定义它
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 TEST_CASE("Test Inotify") {   Mock<IAppManager> appmanager_mock;   Fake(Dtor(appmanager_mock));   Fake(Method(appmanager_mock, notify_add_event));   Fake(Method(appmanager_mock, notify_rename_event));   auto& app_manager = appmanager_mock.get();   SECTION("test add") {     std::string filename = "asd";     std::thread t1([&app_manager, &filename](){       app_manager.notify_add_event(EventType::File, filename);       app_manager.notify_add_event(EventType::File, filename);       app_manager.notify_add_event(EventType::File, filename);     });     t1.join();     Verify(Method(appmanager_mock, notify_add_event)).Exactly(2);   } } 
 
修改之后,不会触发SIGSEGV异常, 而是能正确打印出调用参数
1 2 3 4 5 6 7 Expected pattern: appmanager_mock.notify_add_event( Any arguments ) Expected matches: exactly 2 Actual matches  : 3 Actual sequence : total of 3 actual invocations:                                appmanager_mock.notify_add_event(?, asd)   appmanager_mock.notify_add_event(?, asd)   appmanager_mock.notify_add_event(?, asd) 
 
但对于间接调用的接口,且在单元测试里无法控制变量类型,则没有什么办法,只能保证Extractly准确而不用打印参数值
gmock的方式 gmock使用预先设定调用参数,在调用时再判断,所以不会出现无效引用的问题