OCMock:存根从不匹配签名
OCMock: stub never matches signature
我正在为一个数据源对象编写一个单元测试,它有它惯用的委托对象。
这个对象的作用是从某个网络服务中获取一些数据,然后回调给委托来通知成功。这是代码:
NSString *validProductId = @"34142977";
NSString *validSiteCode = @"someSiteCode";
[[dataSourceDelegateMock expect] dataSource:dataSource didFetchProductData:[OCMArg any] forProductWithId:validProductId];
[dataSource fetchProductWithId:validProductId andSiteCode:validSiteCode];
NSDate *runUntilDate = [NSDate dateWithTimeIntervalSinceNow:networkTimeOut];
while ([runUntilDate timeIntervalSinceNow] > 0) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:runUntilDate];
}
[dataSourceDelegateMock verify];
现在一切正常,只要网络在 10 秒内回复一些数据,测试就会成功。
我知道 这不是某些人测试网络代码的方式。有些人会做不同的事情,有些人会称之为集成测试,但这不是我现在感兴趣的。
问题出在这里:上面的代码可以正常工作,但是每次都会运行 10 秒,尽管网络通常比这快得多。
我现在要做的是在我的while循环中添加另一个条件,其含义是"if we haven't timed out yet AND if the network hasn't replied already"。通过这种方式,我可以使测试在大多数情况下执行得更快。
所以我修改了测试如下:
NSString *validProductId = @"34142977";
NSString *validSiteCode = @"someSiteCode";
__block BOOL dataSourceFetchedData = NO;
[[dataSourceDelegateMock expect] dataSource:dataSource didFetchProductData:[OCMArg any] forProductWithId:validProductId];
[[[dataSourceDelegateMock stub] andDo:^(NSInvocation * invocation) {
dataSourceFetchedData = YES;
}] dataSource:dataSource didFetchProductData:[OCMArg any] forProductWithId:[OCMArg any]];
[dataSource fetchProductWithId:validProductId andSiteCode:validSiteCode];
NSDate *runUntilDate = [NSDate dateWithTimeIntervalSinceNow:networkTimeOut];
while ([runUntilDate timeIntervalSinceNow] > 0 && dataSourceFetchedData == NO) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:runUntilDate];
}
[dataSourceDelegateMock verify];
显然这里的想法是,一旦委托回调被发送到模拟委托对象(didFetchProductData ...),bool 变量将被设置为 YES 并且 while 循环将终止,从而缩短持续时间测试本身。
最后的问题是:无论我做什么,我都无法匹配将在运行时为委托回调调用的签名,所以我放入块中的任何内容都不会被执行。
测试仍然有效,但不会更快。
经过多次调试,我确定了 validProductId 变量的问题。出于某种我无法理解的原因,returned 值永远不会符合我在存根方法时设置的期望值。我怎么知道 ?因为如果我将期望设置为 nil,并强制数据源为 return nil,一切都会正常进行。
我已经尝试了所有我能想到的方法,所以我们将不胜感激。
这是回调的数据源方法:
(void) fetchProductWithId:(NSString *)productId andSiteCode:(NSString *)siteCode {
NSString *urlString = [NSString stringWithFormat:itemApiString,siteCode,productId];
NSURL *url = [NSURL URLWithString:urlString relativeToURL:self.baseUrl];
[self.requestManager GET:url.absoluteString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self.delegate dataSource:self didFetchProductData:responseObject forProductWithId:productId];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self.delegate dataSource:self didFailFetchProductDataForProductId:productId withError:error];
}];
}
如您所见,数据源 return 与传递的 productId 完全相同,所以我真的不明白为什么这与预期的存根方法不匹配。
非常感谢。
这可能是存根和期望相同方法的问题。您可以尝试使用设置 dataSourceFetchedData
变量的块检查参数,并完全删除存根方法。
[[dataSourceDelegateMock expect] dataSource:dataSource didFetchProductData:[OCMArg checkWithBlock:^BOOL(id obj){
dataSourceFetchedData = YES;
return YES;
}] forProductWithId:validProductId];
您可以结合使用 expect
和 stub
,但这种互动并不是大多数人所期望的。 expect 处理对方法的第一次调用,一旦满足,就会变为非活动状态,从而允许存根处理进一步的调用。
也就是说,可以添加预期的操作,我相信这就是您想要的;像这样:
[[[dataSourceDelegateMock expect] andDo:^(NSInvocation * invocation) {
dataSourceFetchedData = YES;
}] dataSource:dataSource didFetchProductData:[OCMArg any]]
我正在为一个数据源对象编写一个单元测试,它有它惯用的委托对象。 这个对象的作用是从某个网络服务中获取一些数据,然后回调给委托来通知成功。这是代码:
NSString *validProductId = @"34142977";
NSString *validSiteCode = @"someSiteCode";
[[dataSourceDelegateMock expect] dataSource:dataSource didFetchProductData:[OCMArg any] forProductWithId:validProductId];
[dataSource fetchProductWithId:validProductId andSiteCode:validSiteCode];
NSDate *runUntilDate = [NSDate dateWithTimeIntervalSinceNow:networkTimeOut];
while ([runUntilDate timeIntervalSinceNow] > 0) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:runUntilDate];
}
[dataSourceDelegateMock verify];
现在一切正常,只要网络在 10 秒内回复一些数据,测试就会成功。
我知道 这不是某些人测试网络代码的方式。有些人会做不同的事情,有些人会称之为集成测试,但这不是我现在感兴趣的。
问题出在这里:上面的代码可以正常工作,但是每次都会运行 10 秒,尽管网络通常比这快得多。
我现在要做的是在我的while循环中添加另一个条件,其含义是"if we haven't timed out yet AND if the network hasn't replied already"。通过这种方式,我可以使测试在大多数情况下执行得更快。
所以我修改了测试如下:
NSString *validProductId = @"34142977";
NSString *validSiteCode = @"someSiteCode";
__block BOOL dataSourceFetchedData = NO;
[[dataSourceDelegateMock expect] dataSource:dataSource didFetchProductData:[OCMArg any] forProductWithId:validProductId];
[[[dataSourceDelegateMock stub] andDo:^(NSInvocation * invocation) {
dataSourceFetchedData = YES;
}] dataSource:dataSource didFetchProductData:[OCMArg any] forProductWithId:[OCMArg any]];
[dataSource fetchProductWithId:validProductId andSiteCode:validSiteCode];
NSDate *runUntilDate = [NSDate dateWithTimeIntervalSinceNow:networkTimeOut];
while ([runUntilDate timeIntervalSinceNow] > 0 && dataSourceFetchedData == NO) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:runUntilDate];
}
[dataSourceDelegateMock verify];
显然这里的想法是,一旦委托回调被发送到模拟委托对象(didFetchProductData ...),bool 变量将被设置为 YES 并且 while 循环将终止,从而缩短持续时间测试本身。
最后的问题是:无论我做什么,我都无法匹配将在运行时为委托回调调用的签名,所以我放入块中的任何内容都不会被执行。 测试仍然有效,但不会更快。
经过多次调试,我确定了 validProductId 变量的问题。出于某种我无法理解的原因,returned 值永远不会符合我在存根方法时设置的期望值。我怎么知道 ?因为如果我将期望设置为 nil,并强制数据源为 return nil,一切都会正常进行。
我已经尝试了所有我能想到的方法,所以我们将不胜感激。 这是回调的数据源方法:
(void) fetchProductWithId:(NSString *)productId andSiteCode:(NSString *)siteCode {
NSString *urlString = [NSString stringWithFormat:itemApiString,siteCode,productId];
NSURL *url = [NSURL URLWithString:urlString relativeToURL:self.baseUrl];
[self.requestManager GET:url.absoluteString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self.delegate dataSource:self didFetchProductData:responseObject forProductWithId:productId];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self.delegate dataSource:self didFailFetchProductDataForProductId:productId withError:error];
}];
}
如您所见,数据源 return 与传递的 productId 完全相同,所以我真的不明白为什么这与预期的存根方法不匹配。
非常感谢。
这可能是存根和期望相同方法的问题。您可以尝试使用设置 dataSourceFetchedData
变量的块检查参数,并完全删除存根方法。
[[dataSourceDelegateMock expect] dataSource:dataSource didFetchProductData:[OCMArg checkWithBlock:^BOOL(id obj){
dataSourceFetchedData = YES;
return YES;
}] forProductWithId:validProductId];
您可以结合使用 expect
和 stub
,但这种互动并不是大多数人所期望的。 expect 处理对方法的第一次调用,一旦满足,就会变为非活动状态,从而允许存根处理进一步的调用。
也就是说,可以添加预期的操作,我相信这就是您想要的;像这样:
[[[dataSourceDelegateMock expect] andDo:^(NSInvocation * invocation) {
dataSourceFetchedData = YES;
}] dataSource:dataSource didFetchProductData:[OCMArg any]]