我一直试图找出如何使用OCMock为这种方法编写单元测试的方法。有人可以帮我吗?
- (void)executeRequest:(NSURLRequest *)request withCompletionHandler:(void (^)(id responseData, NSError *error))completionHandler
{
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error)
{
NSLog(@"Network error occurred: %@", [error localizedDescription]);
dispatch_async(dispatch_get_main_queue(), ^(void) { completionHandler(nil, error);
});
return;
}
if ([response isKindOfClass:NSHTTPURLResponse.class])
{
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200)
{
NSLog(@"Network error occurred. Status code: %ld", (long)statusCode);
return;
}
}
completionHandler(data, nil);
}];
[dataTask resume];
}
答案 0 :(得分:2)
您应该将OCMArg与checkWithBlock或invokeBlockWithArgs一起使用以测试完成处理程序。下面是一个示例:
为可测试实例和必要的模拟添加属性:
@interface SomeClassTests : XCTestCase
@property (nonatomic, strong) SomeClass *testableInstance;
@property (nonatomic, strong) NSURLSession *mockSession;
@property (nonatomic, strong) NSURLRequest *mockRequest;
@property (nonatomic, strong) NSHTTPURLResponse *mockResponse;
@end
设置属性:
- (void)setUp
{
[super setUp];
self.testableInstance = [SomeClass new];
self.mockSession = OCMClassMock([NSURLSession class]);
self.mockRequest = OCMClassMock([NSURLRequest class]);
self.mockResponse = OCMClassMock([NSHTTPURLResponse class]);
OCMStub(ClassMethod([(id)self.mockSession sharedSession])).andReturn(self.mockSession);
}
别忘了拆解时清理:
- (void)tearDown
{
[(id)self.mockSession stopMocking];
self.mockResponse = nil;
self.mockRequest = nil;
self.mockSession = nil;
self.testableInstance = nil;
[super tearDown];
}
让我们测试发生错误的情况:
- (void)testWhenErrorOccuersThenCompletionWithSameError
{
// arrange
NSError *givenError = [[NSError alloc] initWithDomain:@"Domain" code:0 userInfo:nil];
OCMStub([self.mockSession dataTaskWithRequest:[OCMArg any] completionHandler:([OCMArg invokeBlockWithArgs:@"", self.mockResponse, givenError, nil])]);
void (^givenCompletion)(id _Nonnull, NSError * _Nonnull) = ^void(id _Nonnull responseData, NSError * _Nonnull resultError) {
// assert
XCTAssertNil(responseData);
XCTAssertEqual(resultError, givenError);
};
// act
[self.testableInstance executeRequest:self.mockRequest withCompletionHandler:givenCompletion];
}
因此,我们将确保如果发生某些错误,则完成处理程序将在参数处调用相同的错误。
当我们收到一些错误的状态代码时让我们测试:
- (void)testWhenBadStatusCodeThenReturnWithoutCompletion
{
// arrange
OCMStub([self.mockResponse statusCode]).andReturn(403);
OCMStub([self.mockSession dataTaskWithRequest:[OCMArg any] completionHandler:([OCMArg checkWithBlock:^BOOL(id param) {
void (^passedCompletion)(NSData *data, NSURLResponse *response, NSError *error) = param;
passedCompletion(nil, self.mockResponse, nil);
return YES;
}])]);
void (^givenCompletion)(id _Nonnull, NSError * _Nonnull) = ^void(id _Nonnull responseData, NSError * _Nonnull resultError) {
// assert
XCTFail("Shouldn't be reached");
};
// act
[self.testableInstance executeRequest:self.mockRequest withCompletionHandler:givenCompletion];
}
最后让我们测试何时实际获取数据:
- (void)testWhenSuccesThenCompletionWithSameData
{
// arrange
NSData *givenData = [NSData data];
OCMStub([self.mockResponse statusCode]).andReturn(200);
OCMStub([self.mockSession dataTaskWithRequest:[OCMArg any] completionHandler:([OCMArg checkWithBlock:^BOOL(id param) {
void (^passedCompletion)(NSData *data, NSURLResponse *response, NSError *error) = param;
passedCompletion(givenData, self.mockResponse, nil);
return YES;
}])]);
void (^givenCompletion)(id _Nonnull, NSError * _Nonnull) = ^void(id _Nonnull responseData, NSError * _Nonnull resultError) {
// assert
XCTAssertEqual(responseData, givenData);
};
// act
[self.testableInstance executeRequest:self.mockRequest withCompletionHandler:givenCompletion];
}
如果您打开覆盖范围,那么您将看到这样的测试完全覆盖了可测试的代码: