主页做的好之开源团队一般东西还无会见不同。新本子为配合老版本的API

近年来在写OC的单元测试,虽然XCTest已经越来越好了,但是本着mock的支撑或欠缺很多。所以上网查看了生,发现差不多说OCMock不错,去官网看了看,第一及时过去主页做的死去活来尴尬,主页做的好之开源团队一般东西还不见面不同,赶紧用起。

NOTE: 本文翻译自OCMock官网中之同切开教程外链OCMock Test
Origami。

配置OCMock

以此官网及出详尽的步子教程,按着做就哼了。贴个连接http://ocmock.org/ios/

欠篇以的API是OCMock老版本的API,新本子也匹配老版本的API,译者在就此到老版本的API处已经补充加了对应之初本子(OCMock3)的API供读者参考。

开始mock

爱好者

立即首稿子一经读者都能够熟悉使用Xcode5的测试框架XCTest,或者BBD测试工具Kiwi或任何的iOS测试框架

1. mock方法返回值

mock方法返回值这个应该是极其常用之均等种情况了,也是非常简单的同种植状况。示例代码如下:

id mockClass = OCMClassMock([SomeClass class]);
//没有参数的方法
OCMStub([mockClass someMethod]).andReturn(anObject);
//有参数的方法
OCMStub([mockClass someMethod:[OCMArg any]]).andReturn(anObject);

这边要专注的饶是发出参数的艺术,参数是得具体指定的,也就是说只有满足你指定的现实性参数的调用才会于mock指定的返值。例子中之[OCMArg
any]举凡依靠任意参数。

好家伙是mock?差不多就是是绣花枕头

当我们写单元测试的早晚,不可避免的如错过尽可能少的实例化一些具体的机件来保持测试既差而急匆匆。而且保持单元的隔离。在当代之面向对象系统被,测试的机件很可能会见时有发生几乎个因的对象。我们所以mock来替代实例化具体的依赖class。mock是在测试着之一个制假之产生预定义行为之切实对象的替罪羊对象。被测试的组件不晓得里面的异样!你的机件是于一个更充分的体系被让设计之,你得十分有信心之故mock来测试你的组件。

2. 证mock方法给调用

稍微时候要证实我们尽之代码流程是否调用了某个外部的主意,这个时节用OCMock就比较简单来兑现。

id mockClass = OCMClassMock([SomeClass class]);
//...
//some code
//...
OCMVerify([mockClass someMethod]);

倘没有调用了是法吧,会立即抛弃一个坏出。

大的mock使用案例

3. 证mock方法无于调用

假若有点时候呢,我们纪念使验证代码没有调用某个方法,这里以OCMock对这种情景没有支持,我为查看了众资料,最后想发出了一个比取巧的法,但尚算灵光。

static BOOL isCalled = false;
id mockClass = OCMClassMock([SomeClass class]);
OCMStub([mockClass someMethod]).andDo(^(NSInvocation *invocation){
isCalled = YES;
});
//...
//some code
//...
XCTAssertFalse(isCalled);

万一方式让调用了,就以isCalled设置也YES,这样结尾assert的当儿就见面报错。

stub方法

咱因此一个简便的例证来开解释OCMock中貌似的stub语法。

id jalopy = [OCMock mockForClass[Car class]];
 [[[jalopy stub] andReturn:@"75kph"] goFaster:[OCMArg any] units:@"kph"];
 // if returning a scalar value, andReturnValue: can be used

OCMock3 新本子对应API

id jalopy = OCMStrictClassMock([Car class]);
OCMStub([jalopy goFaster:[OCMArg any] units:@"kph"]).andReturn(@"75kph");
// if returning a scalar value, andReturnValue: can be used

其一大概的例子首先从Car类中mock出一个jalopy(老爷车),然后,stub掉goFaster:计被她回到字符串@”75kph”。stub语法可能看起有些意外,但当下是大面积的做法:

ourMockObject stub] whatItShouldReturn ] method:

OCMock3 新本子对应API

OCMStub([ourMockObject method:]).andReturn()

一个不胜重要的认证:注意[OCMArg any]的用法。当指定一个带动参数的章程时,方法为调用并且参数为指定参数的口舌,mock会返回andReturn:指定的价。[OCMArg any]办法告诉stub匹配所有的参数值。举个例子:

[car goFaster:84 units:@"mph"];

匪见面触发stub,因为最后一个参数不配合”kph”.

4. 征mock方法传入的参数

再有的气象用证明传递给外部调用的参数是否吻合预期,示例代码:

id mockClass = OCMClassMock([SomeClass class]);
OCMStub([mockClass someMethod:[OCMArg checkWithBlock:^BOOL(id obj) {
//...
//some code
//...
return YES;
]]);

类方法

OCMock会在mock实例上尚未找到同样名字的实例方法的下失去寻觅同名的好像方式。在名字同样的事态下(类方式与实例方法同名),用classMethod来指定类措施:

[[[[jalopy stub] classMethod] andReturn:@"expired"] checkWarrany];

在OCMock3遭classMethod和instanceMethod的stub方式一样,例如:

id classMock = OCMClassMock([SomeClass class]);
OCMStub([classMock aClassMethod]).andReturn(@"Test string");
// result is @"Test string"
NSString *result = [SomeClass aClassMethod];

5. mock单例

苟我们mock的类似是独单例的语句,那么下前的艺术进行mock是未会见收效之。不过OCMock提供了一个良简单的解决办法,那就算是调用单例返回mock。

id mockClass = OCMClassMock([SomeClass class]);
OCMStub([mockClass instanceMethod]).andReturn(mockClass);``

这么以后,我们虽可健康的开展mock了。

mock类型 – niceMock,partialMock

OCMock提供了几乎种不同档次的mock,每个都来他们一定的应用状况。

之所以这种办法来创造任意mock:

id mockThing = [OCMock mockForClass[Thing class]];

OCMock3 新本子对应API

id mockThing = OCMStrictClassMock([Thing class]);

马上虽是自身所说的‘vanilla’ mock‘vanilla’ mock当调用一个从来不stub的主意的时光会丢来一个可怜。这会得到一个干燥的mock,且以mock的生命周期中每一个法调用都如吃stub掉。(更多信息要看下一样省关于stub)

假若你不思stub很多艺术,用‘nice’ mock‘nice’ mock那个有礼貌而不见面于一个无stub掉的法门被调用的时节丢来特别。

id niceMockThing = [OCMock niceMockForClass[Thing class]];

OCMock3 新本子对应API

id mockThing = OCMClassMock([Thing class]);

末一个mock类型是‘partial’ mock。当一个没stub掉的不二法门给调用了,这个措施会被转发到真的目标上。这是本着mock技术达到之骗,但是挺有因此,当有一些看似不切合为祥和颇好之被stub。

Thing *someThing = [Thing alloc] init];
id aMock = [OCMockObject partialMockForObject:someThing]

OCMock3 新本子对应API

Thing *someThing = [Thing alloc] init];
id aMock = OCMPartialMock(someThing);

证明措施是否让调用

说明办法是否为调用非常简单。这个得据此expect来形成拒绝与认证办法:

id niceMockThing = [OCMock niceMockForClass[Thing class]];
 [[niceMockThing expect] greeting:@"hello"];
 // verify the method was called as expected
 [niceMocking verify];

OCMock3 新本子对应API

id niceMockThing = OCMClassMock([Thing class]);
OCMVerify([niceMockThing greeting:@"hello"]);

当于认证的主意无为调用的时候会扔来异常。如果你用之是XCTest,那么请用XCTAssertNotThrow来包装说明调用。拒绝方法调用也是平等的理,但是会另行道调用的时候丢来异常。就像stub,selector和传递过去说明的参数必须配合调用时候传递过去的参数。用[OCMArg any]得简化我们的做事。

处理block参数

OCMock也堪拍卖block回调参数。block回调通常用于网络代码,数据库代码,或者在另外异步操作着。在是事例中,思考下下面的法子:

- (void)downloadWeatherDataForZip:(NSString *)zip
              callback:(void (^)(NSDictionary *response))callback;

每当是事例中,我们发出一个下载天气减少数量的方,并且将生充斥下来的dictionary代理到一个block的回调中。在测试着,我们通过预定义的气候数据来测试回调处理。这为是明智之测试失败场景365体育网站。你永远不见面理解网络上会回去您哟事物!

// 1. stub using OCMock andDo: operator.
[[[groupModelMock stub] andDo:^(NSInvocation *invoke) {
        //2. declare a block with same signature
        void (^weatherStubResponse)(NSDictionary *dict);
        //3. link argument 3 with with our block callback
        [invoke getArgument:&weatherStubResponse atIndex:3];
        //4. invoke block with pre-defined input
        NSDictionary *testResponse = @{@"high": 43 , @"low": 12};
        weatherStubResponse(groupMemberMock); 
    }]downloadWeatherDataForZip@"80304" callback:[OCMArg any] ];

OCMock3 新本子对应API

// 1. stub using OCMock andDo: operator.
OCMStub([groupModelMock downloadWeatherDataForZip:@"80304" callback:[OCMArg any]]]).andDo(^(NSInvocation *invocation){
        //2. declare a block with same signature
        void (^weatherStubResponse)(NSDictionary *dict);
        //3. link argument 3 with with our block callback
        [invoke getArgument:&weatherStubResponse atIndex:3];
        //4. invoke block with pre-defined input
        NSDictionary *testResponse = @{@"high": 43 , @"low": 12};
        weatherStubResponse(groupMemberMock); 
    });

此的大致思想相当简单,即便如此,他的落实为要有认证:

1.这个mock对象使用带NSInvocation参数的“andDo”方法。一个NSInvocation对象代表一个‘objectivetified’(实在不知道这个什么鬼)表现的方法调用。通过这个NSinvocation对象,使得拦截传递给我们的方法的block参数变得可能。
2.用与我们测试的方法中相同的方法签名声明一个block参数。
3.NSInvocation实例方法"getArgument:atIndex:"将赋值后的块函数传递都原始函数中定义的块函数中。注意:在Objective-C中,传递给任意方法的前两个参数都是“self”和“_cmd”.这是一个运行时的小功能以及用下标来获取NSInvocation参数时我们需要考虑的东西。
4.最后,传递这个回调的预定义字典。

最后

愿意就首文章和例子已经陈述清楚一些OCMock最通用的用法。OCMock站点:http://ocmock.org/features/凡是一个顶好的求学OCMock的地方。mock是单调的但对于一个现代之OO系统却是必须的。如果一个指图很麻烦用mock来测试,这个迹象表明你的筹划得重新考虑了。

相关文章