主页做的好的开源团队一般东西都不会差,新本子也相配老版本的API365体育网站

近来在写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的回调中。在测试中,我们透过预订义的气象数据来测试回调解和管理理。那也是明智的测试退步场景。你永恒不会分晓互联网上会重返您怎么样东西!

// 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是干Baba的而是对于三个当代的OO系统却是必须的。假如三个借助图很难用mock来测试,这几个迹象评释你的安排性要求重新考虑了。

相关文章