为什么我的测试在使用真实参数时“未调用预期方法”失败但在使用`[OCArg isNotNil]时传递?

时间:2014-01-19 02:20:37

标签: objective-c tdd bdd ocmock

我正在使用OCMock测试方法。方法如下:

- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(NSDictionary *)parameters
                        block:(void (^)(id responseObject, NSError *error))block
{
    return [self GET:URLString parameters:parameters success:^(NSURLSessionDataTask * __unused task, id responseObject) {
        block(responseObject, nil);
    } failure:^(NSURLSessionDataTask * __unused task, NSError *error) {
        block(nil, error);
    }];
}

此测试失败,并且“未调用预期方法”:

id sessionManagerPartialMock = [OCMockObject partialMockForObject:[FOOHTTPSessionManager manager]];

NSString *URLstring = @"test";
NSDictionary *parameters = nil;

void (^block)(id, NSError *) = ^(id responseObject, NSError *error) {};

void (^successBlock)(NSURLSessionDataTask *, id) = ^(NSURLSessionDataTask * __unused task, id responseObject) {
    block(responseObject, nil);
};

void (^failureBlock)(NSURLSessionDataTask *, NSError *) = ^(NSURLSessionDataTask * __unused task, NSError *error) {
    block(nil, error);
};

[[sessionManagerPartialMock expect] GET:URLstring parameters:parameters success:successBlock failure:failureBlock];

[sessionManagerPartialMock GET:URLstring parameters:parameters block:block];

[sessionManagerPartialMock verify];
[sessionManagerPartialMock stopMocking];

但这传递了:

id sessionManagerPartialMock = [OCMockObject partialMockForObject:[FOOHTTPSessionManager manager]];

NSString *URLstring = @"test";
NSDictionary *parameters = nil;

void (^block)(id, NSError *) = ^(id responseObject, NSError *error) {};

[[sessionManagerPartialMock expect] GET:URLstring parameters:parameters success:[OCMArg isNotNil] failure:[OCMArg isNotNil]];

[sessionManagerPartialMock GET:URLstring parameters:parameters block:block];

[sessionManagerPartialMock verify];
[sessionManagerPartialMock stopMocking];

为什么第一次测试失败,如何让它通过?

我在GitHub上放了一个示例项目来演示这个问题:https://github.com/paulyoung/OCMockExample

2 个答案:

答案 0 :(得分:0)

我检查了你的回购,我想现在我可以给你很好的答案。

你在测试中尝试做的是块比较,目前在Obj-c世界中这是不可能的。即使你阻止了测试,并且在单例中创建的块看起来相同,它们也不是相同的块。

您可以将失败和成功阻止用作私有属性并在OCMock期望中使用它们来解决此问题。喜欢:

[[sessionManagerPartialMock expect] GET:URLstring parameters:parameters success:sessionManager.successBlock failure:sessionManager.failureBlock];

答案 1 :(得分:0)

正如其他人所说,通过比较块的地址来比较块。两个不同的块 - 即使它们完全相同 - 也不相同。 您仍然可以通过实际调用成功和失败块来使测试更具体,并检查它们是否按预期运行。

据我了解,您想测试

  • 该方法使用两个块调用另一个方法,在调用时,使用
  • 调用原始块
  • 一些响应对象作为第一个,nil作为成功的第二个参数
  • nil作为第一个,NSError*作为失败时的第二个参数

以下是成功案例的测试:

id responseMock = @"responseObject";
__block BOOL blockCalled = NO;

void (^block)(id, NSError *) = ^(id responseObject, NSError *error) {
    XCTAssertNil(error, @"");
    XCTAssertEqualObjects(responseObject, responseMock, @"");
    blockCalled = YES;
};

[[[sessionManagerPartialMock expect] andDo:^(NSInvocation *invocation) {
    void (^successBlock)(NSURLSessionDataTask *, id);
    [invocation getArgument:&successBlock atIndex:4];
    successBlock((id)@"task", responseMock);
}] GET:URLstring parameters:parameters success:[OCMArg isNotNil] failure:[OCMArg isNotNil]];

[sessionManagerPartialMock GET:URLstring parameters:parameters block:block];

[sessionManagerPartialMock verify];
XCTAssert(blockCalled, @"");