尽快用起来,新本子也分外老版本的API

4. 认证mock方法传入的参数

再有的境况需要验证传递给外部调用的参数是否符合预期,示例代码:

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

处理block参数

OCMock也足以拍卖block回调参数。block回调日常用于网络代码,数据库代码,或者在此外异步操作中。在这一个事例中,思考下下边的章程:

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

在这些事例中,大家有一个下载天气裁减数量的法子,并且把下载下来的dictionary代理到一个block的回调中。在测试中,大家通过预定义的气象数据来测试回调处理。这也是明智的测试败北场景。你永远不会明白网络上会再次来到您如何东西!

// 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.最后,传递这个回调的预定义字典。

2. 证实mock方法被调用

稍微时候需要证实我们实践的代码流程是否调用了某个外部的法门,这么些时候用OCMock就相比简单来兑现。

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

设若没有调用过这一个措施的话,会及时抛一个充足出来。

爱好者

这篇小说假若读者都能熟知使用Xcode5的测试框架XCTest,或者BBD测试工具Kiwi或其他的iOS测试框架

开始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);

配置OCMock

本条官网上有详细的步骤教程,按着做就好了。贴个连接http://ocmock.org/ios/

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”.

1. mock方法再次回到值

mock方法再次回到值这个相应是最常用的一种情状了,也是分外简单的一种意况。示例代码如下:

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

此处需要注意的就是有参数的点子,参数是足以切切实实指定的,也就是说唯有满意你指定的实际参数的调用才会被mock指定的再次来到值。例子中的[OCMArg
any]是指任意参数。

类方法

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了。

该著作使用的API是OCMock老版本的API,新本子也匹配老版本的API,译者在用到老版本的API处已经添加了对应的新本子(OCMock3)的API供读者参考。

如今在写OC的单元测试,即便XCTest已经越来越好了,不过对mock的支撑仍然欠缺很多。所以上网查了下,发现多说OCMock不错,去官网看了看,第一随即过去主页做的很窘迫,主页做的好的开源团队一般东西都不会差,赶紧用起来。

最后

仰望这篇作品和例子已经陈述清楚部分OCMock最通用的用法。OCMock站点:http://ocmock.org/features/是一个最好的就学OCMock的地方。mock是枯燥的然则对于一个现代的OO系统却是必须的。如若一个借助图很难用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的时候就会报错。

NOTE: 本文翻译自OCMock官网中的一片教程外链OCMock Test
Origami

评释办法是否被调用

表达格局是否被调用异常简单。那么些可以用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]可以简化大家的做事。

大规模的mock使用案例

什么样是mock?差不多就是绣花枕头

当我们写单元测试的时候,不可避免的要去尽可能少的实例化一些有血有肉的零部件来保障测试既短又快。而且保持单元的割裂。在当代的面向对象系统中,测试的组件很可能会有多少个依靠的靶子。我们用mock来取代实例化具体的倚重class。mock是在测试中的一个制假的有预定义行为的有血有肉目的的替罪羊对象。被测试的零件不知晓其中的差异!你的零部件是在一个更大的连串中被设计的,你能够很有信心的用mock来测试你的零件。

相关文章