注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Google Mock进阶篇 [3] (Google Mock Cookbook译文)  

2012-04-26 21:34:17|  分类: C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Using Matchers

Matching Argument Values Exactly

    你可以精确指定一个Mock函数期望的参数是什么:

using ::testing::Return;

...

  EXPECT_CALL(foo, DoThis(5))

      .WillOnce(Return('a'));

  EXPECT_CALL(foo, DoThat("Hello", bar));

Using Simple Matchers

    你可以用Matchers去匹配有一定特征的参数:

using ::testing::Ge;

using ::testing::NotNull;

using ::testing::Return;

...

EXPECT_CALL(foo, DoThis(Ge(5)))  // The argument must be >= 5.

    .WillOnce(Return('a'));

EXPECT_CALL(foo, DoThat("Hello", NotNull()));

// The second argument must not be NULL.

    一个常用的Matcher_,它表示匹配任何参数:

using ::testing::_;

using ::testing::NotNull;

...

  EXPECT_CALL(foo, DoThat(_, NotNull()));

Combining Matchers

    你可以使用已有的AllOf()AnyOf()Not(),组合产生一些复杂的Matchers

using ::testing::AllOf;

using ::testing::Gt;

using ::testing::HasSubstr;

using ::testing::Ne;

using ::testing::Not;

...

  // The argument must be > 5 and != 10.

  EXPECT_CALL(foo, DoThis(AllOf(Gt(5),

                                Ne(10))));

 

  // The first argument must not contain sub-string "blah".

  EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")),

                          NULL));

Casting Matchers

    Google Matchers都是静态类型的,即如果你错误地使用Matcher的类型( 比如,如果你使用Eq(5)去匹配一个string参数 ),编译器会报错。这也是为你好。

    但有时,你知道你自己在做什么,并希望编译器放你一马。举例来说:如果你有一个针对long类型的Matcher,但你想匹配的是int。虽然这两个类型不同,但实际上用Matcher<long>去匹配int并没有错,毕竟,我们可以先将int参数转换成long,再传给Matcher

    为了支持这种需求,Google Mock提供了SafeMatcherCast<T>(m)函数。它将一个Matcher m转换成Matcher<T>。为了保证它是安全的转换,Google Mock如检查( Um接受的参数 )

1.  T类型可以隐式地转换为U类型。

2.  TU都是内置数值类型时( boolintegersfloat ),从TU的转换是无损的( 换句话说,用T类型的任何值都可以用U类型表示 )

3.  U是一个引用,T必须也是一个引用( 因为底层的Matcher也许会对U类型参数的地址感兴趣 )

如果上述条件中任何一个没满足,是不会通过编译的。

下面是一个例子:

using ::testing::SafeMatcherCast;

 

// A base class and a child class.

class Base { ... };

class Derived : public Base { ... };

 

class MockFoo : public Foo {

 public:

  MOCK_METHOD1(DoThis, void(Derived* derived));

};

...

 

  MockFoo foo;

  // m is a Matcher<Base*> we got from somewhere.

  EXPECT_CALL(foo, DoThis(SafeMatcherCast<Derived*>(m)));

如果你发现SafeMatcherCast<T>(m)太严格,你可以用一个类似的函数MatcherCast<T>(m)。两个函数的区别是如果static_cast可以将T类型转换成类型U,那么MatcherCast就可以转换。

MatcherCast对你凌驾于C++类型系统之上很重要的( static_cast不总是安全的,比如它可以丢弃一部分信息 ),所以要小心不要误用/滥用它。

Selecting Between Overloaded Functions

    如果你期望一个重载函数被调用,编译器需要你来指明你指的是重载函数中的哪一个。

    消除一个对象上关于常量的重载的歧义,使用Const()来指明。

using ::testing::ReturnRef;

 

class MockFoo : public Foo {

...

MOCK_METHOD0(GetBar, Bar&());

MOCK_CONST_METHOD0(GetBar, const Bar&());

};

...

 

MockFoo foo;

Bar bar1, bar2;

EXPECT_CALL(foo, GetBar())         // The non-const GetBar().

    .WillOnce(ReturnRef(bar1));

EXPECT_CALL(Const(foo), GetBar())  // The const GetBar().

    .WillOnce(ReturnRef(bar2));

    ( Const()Google Mock定义,并返回它的参数的const引用。 )

    消除函数个数相同,但参数类型不同重载函数的歧义,你也许需要精确指定一个Matcher的匹配类型,在Matcher<type>中修饰你的Matcher,或是使用一个类型是确定的Matcher( TypedEq<type>An<type>()等等 ):

using ::testing::An;

using ::testing::Lt;

using ::testing::Matcher;

using ::testing::TypedEq;

 

class MockPrinter : public Printer {

 public:

  MOCK_METHOD1(Print, void(int n));

  MOCK_METHOD1(Print, void(char c));

};

 

TEST(PrinterTest, Print) {

  MockPrinter printer;

 

  EXPECT_CALL(printer, Print(An<int>()));            // void Print(int);

  EXPECT_CALL(printer, Print(Matcher<int>(Lt(5))));  // void Print(int);

  EXPECT_CALL(printer, Print(TypedEq<char>('a')));   // void Print(char);

 

  printer.Print(3);

  printer.Print(6);

  printer.Print('a');

}

Performing Different Actions Based on the Arguments

    当一个Mock函数被调用时,最后一个有效的期望会被匹配( “新规则覆盖老规则” )。所以你可以让一个函数根据它的参数值去做不同的事,如下:

using ::testing::_;

using ::testing::Lt;

using ::testing::Return;

...

  // The default case.

  EXPECT_CALL(foo, DoThis(_))

      .WillRepeatedly(Return('b'));

 

  // The more specific case.

  EXPECT_CALL(foo, DoThis(Lt(5)))

      .WillRepeatedly(Return('a'));

    现在,如果foo.DoThis()被调用时参数值小于5,就会返回’a’,否则返回’b’

Matching Multiple Arguments as a Whole

    有时候只能单独去匹配参数是不够的。比如,我们想设置第一个参数的值必须小于第二个参数的值。With子句可以让我们将Mock函数的参数做为一个整体去匹配。比如:

using ::testing::_;

using ::testing::Lt;

using ::testing::Ne;

...

EXPECT_CALL(foo, InRange(Ne(0), _))

    .With(Lt());

    上面代码意为InRange第一个参数必须非0,并且必须小于第二个参数。

    With内的语句必须是一个Match<tr1::tuple<A1, ..., An> >类型的Matcher,其中A1,..., An是函数参数的类型。

    你还可以用AllArgs(m)来代替将m写在.With()里的写法。两种形式意义相同,但是.With(AllArgs(Lt())).With(Lt())更具有可读性。

    你可以用Args<k1, ..., kn>(m) 根据m规则来匹配n个选择的参数。比如:

using ::testing::_;

using ::testing::AllOf;

using ::testing::Args;

using ::testing::Lt;

...

EXPECT_CALL(foo, Blah(_, _, _))

    .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt())));

    为了方便和举例起见,Google Mock提供了关于2-tuplesMatchers,包括上面的Lt() Matcher。可以到CheatSheet中找到完整的列表。

    注意如果你想将这些参数传递给你自己的Predicate( 比如.With(0, 1)(Truly(&MyPredicate))),你的必须以tr1::tuple做为它的参数。Google Mock会将n个选中的参数作为单个tuple传递给Predicate

Using Matchers as Predicates

    你是否注意到Matcher只是一个好看一些的Pridicate,许多已有的算法可将Predicates作为参数( 比如,那些在STL<algorithm>中定义的算法),如果Google Mock Matchers不能参与到其中,那将是一个遗憾。

    幸运的地,你可以将一元Predicate仿函数放到Matches()函数中来使用Matcher,比如:

#include <algorithm>

#include <vector>

 

std::vector<int> v;

...

// How many elements in v are >= 10?

const int count = count_if(v.begin(), v.end(), Matches(Ge(10)));

    因为你可通过将简单的matchers组合来产生复杂的matchers,那么这就给你了一种构造组合Predicates的方便方法( 与在STL中使用<functional>中的函数一样 )。比如,下面是一个任何满足 >=0<=100!=50Predicate

Matches(AllOf(Ge(0), Le(100), Ne(50)))

  评论这张
 
阅读(2321)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017