这是一个简单的指南,教您如何将模拟类注入产品代码中,并让您的产品类在 CppUTest 单元框架下可测试。
下图是类之间的关系。ProductClassB 依赖于 ProductClassA(ProductClassB 调用 ProductClassB.method() 中的 ProductClassA.method1()),现在当我们对 ProductClassB 进行单元测试时,应该模拟 ProductClassA。
下面的代码展示了如何使用 CppUTest 使用新方法来模拟依赖的类。
ProductClassA 有一些方法,如果您希望这些方法可以被模拟,则应将这些方法声明为虚拟方法。
ProductClassA.hpp:
#ifndef _INCLUDE_PRODUCT_A_CLASS_ #define _INCLUDE_PRODUCT_A_CLASS_ #include <string> class ProductClassA { public : ProductClassA() { } ~ProductClassA() { } public : virtual int method1(const std::string& arg1); virtual int method2(const std::string& arg1); };#endif ProductClassA.cpp:
#include <iostream> #include "ProductClassA.hpp" int ProductClassA::method1(const std::string& arg1) { std::cout << arg1 << " ProductClassA class method1" <<std::endl; return 0; }int ProductClassA::method2(const std::string& arg1) { std::cout << arg1 << " ProductClassA class method2" <<std::endl; return 0; }如果你想在对 ProductClassB 进行单元测试时模拟依赖的类 ProductClassA,则应在 ProductClassB 中声明一个具有引用类型的私有 ProductClassA 变量,并且在 ProductClassB 中可以有两个构造函数,一个用于产品代码,一个用于单元测试代码,如下所示。
ProductClassB.hpp:
#include <string> #include "ProductClassA.hpp" class ProductClassB { public : // for unit test ProductClassB(ProductClassA& ainstance): _ainstance(ainstance) { } // for product code ProductClassB(): _ainstance(ProductClassA()) { } ~ProductClassB() { } public : int method(); private : ProductClassA& _ainstance; };ProductClassB.cpp:
#include "ProductClassB.hpp" #include <iostream> int ProductClassB::method() { std::cout<< "this is B class method"<<std::endl; return this ->_ainstance.method1("B invoke"); }ProductClassAMock类是ProductClassA的派生类,其中的方法将以mock的方式重新实现。
ProductClassAMock.hpp:
#include "ProductClassA.hpp" class ProductClassAMock : public ProductClassA {public : virtual int method1(const std::string& arg1); virtual int method2(const std::string& arg1); };ProductClassAMock.cpp:
#include "ProductClassAMock.hpp" #include <iostream> #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" int ProductClassAMock::method1(const std::string& arg1) { std::cout << arg1 << " ProductClassAMock method1"<<std::endl; mock().actualCall("method1"); return 0; }int ProductClassAMock::method2(const std::string& arg1) { mock().actualCall("method2"); return 0; }ProductClassB 的单元测试将使用测试构造函数在 bInstance 中用模拟类 ProductClassAMock 初始化 _ainstance,然后根据 C++ 多态机制,将 _ainstance.method1() 替换为类 ProductClassAMock 中的 method1。
ProductClassB_unittests.cpp:
#include "ProductClassB.hpp" #include "ProductClassAMock.hpp" #include "CppUTest/CommandLineTestRunner.h" #include "CppUTest/TestHarness.h" #include "CppUTestExt/MockSupport.h" TEST_GROUP(BClassFooTests) { void teardown() { mock().clear(); } }; TEST(BClassFooTests, MockAsExpected) { mock().expectOneCall("method1"); ProductClassAMock aMockInstance; ProductClassB bInstance(aMockInstance); bInstance.method(); mock().checkExpectations(); }int main(int ac, char ** av) { return CommandLineTestRunner::RunAllTests(ac, av); }产品代码只需使用ProductClassB的产品构造函数,bInstance._ainstance将使用真实的类ProductClassA进行初始化。
main.cpp:
#include "ProductClassB.hpp" int main() { ProductClassB bInstance(); bInstance.method(); return 0; }如何构建代码:
# build main g++ ProductClassA.cpp ProductClassB.cpp main.cpp -o main# build unit test g++ ProductClassA.cpp ProductClassB.cpp ProductClassAMock.cpp ProductClassB_unittests.cpp -lstdc++ -lCppUTest -lCppUTestExt -o testrunner参考: