整理自:https://blog.csdn.net/tony_wong/article/details/
mock工具介绍
mock工具用于指定函数的行为。可以对入参进行校验,对出参进行设定,指定函数的返回值。
相关概念
mock规范
每个MOCKER(function)开始,跟着一系列的.stubs/.with/.will等的内容整体,称为一个mock规范。
核心关键字
指stubs/defaults/expects/before/with/after/will/then/id等这些直接跟在点后面的关键字。
拓展关键字
指once()/eq()/check()/returnValue()/repeat()等这些作为核心关键字参数的关键字
mock模板
TEST(mockcpp detail sample) {
MOCKER(function) / MOCK_METHOD(mocker, method) .stubs() / defaults() / expects(never() | once() | exactly(3) | atLeast(3) | atMost(3) ) [.before("some-mocker-id")] [.with( any() | eq(3) | neq(3) | gt(3) | lt(3) | spy(var_out) | check(check_func) | outBound(var_out) | outBoundP(var_out_addr, var_size) | mirror(var_in_addr, var_size) | smirror(string) | contains(string) | startWith(string) | endWith(string) )] [.after("some-mocker-id")] .will( returnValue(1) | repeat(1, 20) | returnObjectList(r1, r2) | invoke(func_stub) | ignoreReturnValue() | increase(from, to) | increase(from) | throws(exception) | die(3)) [.then(returnValue(2))] [.id("some-mocker-id")] }
讯享网
拓展关键字分类
expects里面的叫匹配关键字(Matcher)
with里面的叫约束关键字(Constraint)
will/then里面的叫桩关键字(Stub)
spy
用于监事执行该被mock的函数function被调用时传入的值,会保存在var_out中,供用例中其他地方使用
outBound
用于设置函数function的出参的值。多半是把该值作为后面部分被测代码的输入。
outBoundP
与outBound的作用相同,只是用于数组的情况。
mirror
用于对数组类型类型的入参进行检查
check
die
表示程序退出,并返回指定的值,模拟一个函数调用崩溃的情况
increase(from,to)
表示一次返回from到to的对象,任何重载了++运算符的对象都可以用
outBound和outBoundP
可以带一个约束参数,永不对参数进行检查
使用说明
mock c函数或者类的静态成员方法用MOCKER
mock类的非静态成员方法使用形式如下
讯享网MockObject<MyClass> mocker; MOCK_METHOD(mocker, method);
其中MyClass为被mock的对象,method为被mock对象的类成员方法
MOCKER/MOCKER_METHOD之后是stubs、defaults或者expects,必有其一
stubs 表示指定函数的行为,不校验次数
expect与stubs的区别是校验次数
(.expects(once())/ .expects(never()) / .expects(exactly(123))) defaults 表示定义一个默认的mock规范,但它优先级很低;如果后面有stubs或者expects重新指定函数行为,就会按照新指定的来运行。(一般用在setup中)
用will指定函数的返回值
如果指定20次调用都返回1,则使用:
.will(repeat(1, 20));
如果指定第1次返回1,第2次返回2,第3次返回3,则使用:
讯享网.will(returnValue(1)) .then(returnValue(2)) .then(returnValue(3))
ps 第4次之后的都返回3
用id给一个mock规范指定一个名字,然后可以用after、before执行多个mock应该的调用顺序
注意before在with之前,after在with之后,id在整个mock规范的最后
使用mockcpp时,检验是否按照mock规范进行调用,应该用:GlobalMockObject::verify(); verify之后,会自动执行reset。
如果是对象的mock,应该用mocker.verify()。
如果要对某个函数指定多个不同的行为
调用入参1,2时,返回30;调用入参3,4时,返回700。写法如下:
MOCKER(add) .stubs() .with(eq(1), eq(2)) .will(returnValue(30))
讯享网MOCKER(add) .stubs() .with(eq(3), eq(4)) .will(returnValue(700))
如果期望校验次数
MOCKER(add) .stubs() .with(eq(3), eq(4)) .will(returnValue(700)) .expects(once())
如果期望控制调用顺序,必须第一次调用参数是1、2,第二次是3、4,那么可以这样写:
讯享网MOCKER(add) .stubs() .with(eq(1), eq(2)) .will(returnValue(30)) .id("first"); MOCKER(add) .stubs() .with(eq(3), eq(4)) .after("first") .will(returnValue(700))
指出出参的方法
函数
void function(int* val) {
}
指定出参写法:
讯享网int expect = 10; MOCKER(function) .stubs() .with(outBoundP(&expect, sizeof(expect)));
对同一个函数指定多个mock规范。
如测试函数 void function(int in, int &out),前面一个是入参,后面一个是出参,希望in为1时,输出out为100; in为2时,输出out为3,写法如下:
int out = 100; MOCER(function) .expects(once()) .with(eq(1), outBound(out)); out = 3; MOCKER(function) .expects(once()) .with(eq(2), outBound(out));
假设你把eq(1)、eq(2)写为any(),那么mockcpp会判断你的两个调用function(1,out)和function(2, out)都符合第1个mock规范,从而报告与你的定义次数1不匹配。
对同一个函数指定的多个mock规范有规律
假如mock的函数是void function(int in),希望它依次以0、1、2…10为入参被调用,可以借用循环来写:
讯享网MOCKER(function) .expects(once()) .with(eq(0)) .id("0"); for (int i = 1; i <= 10; i ++) {
MOCKER(function) .expects(once()) .with(eq(i)) .after(string(i - 1)) .id(string(i)); }
spy 约束关键字
spy用于监视。监视test在调用func时,传入的值是多少。
void func(int var) {
} void test() {
} TEST(sample, test) {
int var; MOCKER(func) .stubs() .with(spy(var)) .with(eq(10)) test(); ASSERT_EQ(var, 10); }
check 约束关键字的用法
讯享网struct AA {
int a; int b; }; void func(int in, AA* p) {
} bool checkFunc(AA *p) {
if (p->b == 10) {
return true; } return false; } TEST(sample,test) {
MOCKER(func) .stubs() .with(any(), check(checkFunc)); func(in, p); }
例2:如果需要检查b是否小与某一个给定的数,而且有多个用例,每个用例中与b比较的数不同,则可以使用仿函数的方式。
struct CheckFunctor {
CheckFunctor(int _base):base(_base) {
} bool operator() (AA *p) {
if (p->b < base) return true; return false; } int base; }; TEST(Sample, shouldLessThan100) {
MOCKER(func) .stubs() .with(any, check(CheckFunctor(100))); func(in, p); } TEST(Sample, shouldLessThan200) {
MOCKER(func) .stubs() .with(any(), check(CheckFunctor(200))); func(in, p); }
只要打桩了,那就不会运行原函数,会与mock规范匹配,运行桩
例:对于入参add为1,2的情况打桩,如果调用了入参为2、3的情况,则会在报告调用允许的mock规范
讯享网TEST(Sample, test) {
MOCKER(add) .expects(onec()) .with(eq(1), eq(2)) .will(returnValue(100)); ASSERT_EQ(100, add(1, 2)); ASSERT_EQ(50, add(2, 3)); }
带有返回值的函数,MOCKER后面必须有will,否则mockcpp认为没有返回值,检验时会发现类型不匹配
#示例
#include <stdio.h> #include <iostream> #include <string> #include "gtest/gtest.h" #include "mockcpp/mockcpp.hpp" #include "../src/Sample.h" /* mock 规范:每个MOCKER(function)开始,跟一系列的.stubs、.with、.will等的内容的整体,称为一个mock规范。 核心关键字:指stubs/defaults/expects/before/with/after/will/then/id等这些直接跟在点后面的关键字。 扩展关键字:指once()/eq()/check()/returnValue()/repeat()等这些作为核心关键字参数的关键字。 下面,请看两段mockcpp的使用规范示例代码,其中带“/”或者“|”的表示在该位置可能有多种选择;带中括号的表示是可选的。 */ /* TEST(mockcpp detail sample) { MOCKER(function) / MOCK_METHOD(mocker, method) .stubs() / defaults() / expects(never() | once() | exactly(3) | atLeast(3) | atMost(3) ) [.before("some-mocker-id")] [.with( any() | eq(3) | neq(3) | gt(3) | lt(3) | spy(var_out) | check(check_func) | outBound(var_out) | outBoundP(var_out_addr, var_size) | mirror(var_in_addr, var_size) | smirror(string) | contains(string) | startWith(string) | endWith(string) )] [.after("some-mocker-id")] .will( returnValue(1) | repeat(1, 20) | returnObjectList(r1, r2) | invoke(func_stub) | ignoreReturnValue() | increase(from, to) | increase(from) | throws(exception) | die(3)) [.then(returnValue(2))] [.id("some-mocker-id")] } */ class SampleTest : public ::testing::Test { protected: static void SetUpTestCase() { std::cout << "SampleTest SetUpTestCase" << std::endl; } static void TearDownTestCase() { std::cout << "SampleTest TearDownTestCase" << std::endl; } virtual void SetUp() { std::cout << "SampleTest SetUp"<<std::endl; } virtual void TearDown() { std::cout << "SampleTest TearDown"<<std::endl; } }; TEST(SampleTest0, Test0) { EXPECT_TRUE(10 == CallFunc1(10)); } //不打桩测试 TEST_F(SampleTest, Test0) { //bool 类型检查 EXPECT_TRUE(10 == CallFunc1(10)); EXPECT_FALSE(10 != CallFunc1(10)); //数值类型检查 EXPECT_EQ(10, CallFunc1(10)); EXPECT_NE(9, CallFunc1(10)); EXPECT_LT(9, CallFunc1(10)); EXPECT_LE(10, CallFunc1(10)); EXPECT_GT(11, CallFunc1(10)); EXPECT_GE(10, CallFunc1(10)); //bool 类型检查 ASSERT_TRUE(10 == CallFunc1(10)); ASSERT_FALSE(10 != CallFunc1(10)); //数值类型检查 ASSERT_EQ(10, CallFunc1(10)); ASSERT_NE(9, CallFunc1(10)); ASSERT_LT(9, CallFunc1(10)); ASSERT_LE(10, CallFunc1(10)); ASSERT_GT(11, CallFunc1(10)); ASSERT_GE(10, CallFunc1(10)); } //不打桩测试 TEST(SampleTest2, Test0) { EXPECT_STREQ("hello world", CallFunc2("hello world")); EXPECT_STRNE("hello world", CallFunc2("hello asm")); EXPECT_STRCASEEQ("hello world", CallFunc2("HELLO WORLD")); EXPECT_STRCASENE("hello world", CallFunc2("HELLO ASM")); ASSERT_STREQ("hello world", CallFunc2("hello world")); ASSERT_STRNE("hello world", CallFunc2("hello asm")); ASSERT_STRCASEEQ("hello world", CallFunc2("HELLO WORLD")); ASSERT_STRCASENE("hello world", CallFunc2("HELLO ASM")); } //打桩测试 ---基本打桩1 TEST_F(SampleTest, Test1) { MOCKER(Func1).stubs().will(returnValue(101)); EXPECT_EQ(101, CallFunc1(10)); GlobalMockObject::verify(); } //打桩测试 ---基本打桩2 TEST(SampleTest3, Test0) { char* mockstr = "hello asm"; char* mockstr2 = "hello world"; MOCKER(Func2).stubs().will(returnValue(mockstr)); EXPECT_STREQ(mockstr, CallFunc2(mockstr)); EXPECT_STRNE(mockstr2, CallFunc2(mockstr)); GlobalMockObject::verify(); } //打桩测试 --- 返回值-根据调用次数控制返回值-指定20次调用都返回1 TEST_F(SampleTest, Test2) { MOCKER(Func1).stubs().will(repeat(1, 20)); for (int i = 0; i < 20; i++) { EXPECT_EQ(1, CallFunc1(10)); } // EXPECT_EQ(1, CallFunc1(10)); 超过20次执行时会报错 GlobalMockObject::verify(); } //打桩测试 --- 返回值-根据调用次数控制返回值-第一次返回1, 第2次返回2, 第3次返回3 TEST_F(SampleTest, Test3) { MOCKER(Func1).stubs() .will(returnValue(1)) .then(returnValue(2)) .then(returnValue(3)); for (int i = 0; i < 3; i++) { EXPECT_EQ(i+1, CallFunc1(i)); } EXPECT_EQ(3, CallFunc1(4)); GlobalMockObject::verify(); } //打桩测试 --- 返回值-根据调用次数控制返回值-第一次返回1, 第2次返回2, 第3次返回3 TEST_F(SampleTest, Test4) { MOCKER(Func1).stubs() .will(returnValue(1)) .then(returnValue(2)) .then(returnValue(3)); for (int i = 0; i < 3; i++) { EXPECT_EQ(i+1, CallFunc1(i)); } EXPECT_EQ(3, CallFunc1(4)); GlobalMockObject::verify(); } //打桩测试 --- 返回值-对某个函数指定多个不同的行为 (调用入参1时,返回10;调用入参3时,返回30) TEST_F(SampleTest, Test5) { MOCKER(Func1).stubs() .with(eq(1)) .will(returnValue(10)); MOCKER(Func1) .stubs() .with(eq(3)) .will(returnValue(30)); EXPECT_EQ(10, CallFunc1(1)); EXPECT_EQ(30, CallFunc1(3)); GlobalMockObject::verify(); } //打桩测试 --- 调用-对某个函数指定多个不同的行为 (控制调用次数) TEST_F(SampleTest, Test6) { MOCKER(Func1) .expects(once()) .with(eq(1)) .will(returnValue(10)); EXPECT_EQ(10, CallFunc1(1)); // EXPECT_EQ(30, CallFunc1(3)); GlobalMockObject::verify(); } //打桩测试 --- 调用-对某个函数指定多个不同的行为,控制调用次数(第1次必须调用Func1(1),第2次必须调用Func1(2)) TEST_F(SampleTest, Test7) { MOCKER(Func1) .expects(atLeast(1)) .with(eq(1)) .will(returnValue(10)) .id("asm"); MOCKER(Func1) .expects(atLeast(1)) .with(eq(2)) .after("asm") .will(returnValue(20)); // EXPECT_EQ(10, CallFunc1(2)); 这样就报错了,必须先调用1 EXPECT_EQ(10, CallFunc1(1)); EXPECT_EQ(20, CallFunc1(2)); GlobalMockObject::verify(); } //打桩测试 --- 指定出参outBoundP TEST_F(SampleTest, Test8) { char* outbuf = "hello asm"; MOCKER(Func3) .expects(once()) .with(outBoundP(outbuf, strlen(outbuf))) .will(returnValue(0)); char out[64] = {0}; CallFunc3(out, sizeof(out)); EXPECT_STREQ("hello asm", out); GlobalMockObject::verify(); } //打桩测试 --- 指定出参outBound TEST_F(SampleTest, Test9) { int outInt = 100; MOCKER(Func4) .stubs() .with(outBound(outInt)) // 这个地方参数为引用可以mock成功, 指针不行 .will(returnValue(0)); int outIntV = 10; CallFunc4(outIntV); EXPECT_EQ(100, outIntV); GlobalMockObject::verify(); } //打桩测试 --- 同一个函数指定多个规范 TEST_F(SampleTest, Test10) { int out = 100; MOCKER(Func5) .expects(once()) .with(eq(1), outBound(out)) .will(returnValue(0)); out = 3; MOCKER(Func5) .expects(once()) .with(eq(2), outBound(out)) .will(returnValue(0)); int outv = 11; CallFunc5(1, outv); EXPECT_EQ(100, outv); CallFunc5(2, outv); EXPECT_EQ(3, outv); GlobalMockObject::verify(); } //打桩测试 --- 同一个函数指定多个有规律的规范 TEST_F(SampleTest, Test11) { int r1 = 0; MOCKER(Func5) .expects(once()) .with(eq(0), outBound(r1)) .will(returnValue(0)) .id("0"); char preid[16] = {0}; char id[16] = {0}; for (int i = 1; i <= 10; i++) { int val = i; sprintf(preid, "%d", i-1); sprintf(id, "%d", i); MOCKER(Func5) .expects(once()) .with(eq(i), outBound(val)) .after(preid) .will(returnValue(0)) .id(id); } for (int i = 0 ; i <= 10; i++) { int val = 999; CallFunc5(i, val); EXPECT_EQ(i, val); } GlobalMockObject::verify(); } //打桩测试 ---监视被调用的值 TEST_F(SampleTest, Test12) { int var = 0; MOCKER(Func1) .stubs() .with(spy(var)) .will(returnValue(0)); CallFunc1(11); EXPECT_EQ(11, var); GlobalMockObject::verify(); } bool checkFunc(int var); bool checkFunc(int var) { if (var < 3) { return true; } else { return false; } } //打桩测试 ---定制化的参数检查 TEST_F(SampleTest, Test13) { MOCKER(Func3) .stubs() .with(any(), checkWith(checkFunc)) //check编译会报错,改用checkWith .will(returnValue(0)); char buf[16] = {0}; CallFunc3(buf, 2); GlobalMockObject::verify(); } // 实现一个仿函数类,即重载“()”运算符的类。 struct CheckFunctor { CheckFunctor(int _base) : base(_base){} bool operator ()(int p) { if (p < base) return true; return false; } int base; }; //打桩测试 ---定制化的参数检查 - 如果需要检查b是否小于某个给定的数,而且有多个用例,每个用例中与b比较的数不同,则可以使用仿函数的方式 TEST_F(SampleTest, Test14) { MOCKER(Func3) .stubs() .with(any(), checkWith(CheckFunctor(100))) .will(returnValue(0)); char buf[16] = {0}; CallFunc3(buf, 99); GlobalMockObject::verify(); MOCKER(Func3) .stubs() .with(any(), checkWith(CheckFunctor(50))) .will(returnValue(0)); CallFunc3(buf, 30); GlobalMockObject::verify(); }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/56412.html