Gam*_*Dev 5 unit-testing objective-c ocmock stubs nsurlsession
我有一个名为ITunesAlbumDataDownloader的网络类
@implementation AlbumDataDownloader
- (void)downloadDataWithURLString:(NSString *)urlString
completionHandler:(void (^)(NSArray *, NSError *))completionHandler
{
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
NSArray *albumsArray = [self parseJSONData:data];
completionHandler(albumsArray, error);
}];
[dataTask resume];
}
- (NSArray *)parseJSONData:(NSData *)data {
NSMutableArray *albums = [[NSMutableArray alloc] init];
...
...
// Return the array
return [NSArray arrayWithArray:albums];
}
@end
Run Code Online (Sandbox Code Playgroud)
我需要为此创建一个单元测试,它执行以下操作:
//预期的JSON响应
NSData *jsonResponse = [self sampleJSONData];
Run Code Online (Sandbox Code Playgroud)
要记住的其他要点是我需要使用假的JSON数据"jsonResponse"将NSURLSession模拟到downloadDataWithURLString:completionHandler:方法,而不调用实际的网络请求.
我尝试了各种不同的东西,但我无法解决这个问题,我认为这是伪造请求和块的组合,这让我很困惑.
这是我试过的两个测试方法的例子(我实际上尝试了很多其他的方法,但这就是我现在剩下的):
- (void)testValidJSONResponseGivesAlbumsAndNilError {
// Given a valid JSON response containing albums and an AlbumDataDownloaderTests instance
// Expected JSON response
NSData *jsonResponse = [self sampleJSONDataWithAlbums];
id myMock = [OCMockObject mockForClass:[NSURLSession class]];
[[myMock expect] dataTaskWithRequest:OCMOCK_ANY
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error)
{
}];
[myMock verify];
}
Run Code Online (Sandbox Code Playgroud)
和
- (void)testValidJSONResponseGivesAlbumsAndNilError {
// Given a valid JSON response containing albums and an AlbumDataDownloaderTests instance
// Expected JSON response
NSData *jsonResponse = [self sampleJSONDataWithAlbums];
id myMock = [OCMockObject mockForClass:[AlbumDataDownloader class]];
[[[myMock stub] andReturn:jsonResponse] downloadDataWithURLString:OCMOCK_ANY
completionHandler:^(NSArray *response, NSError *error)
{
}];
[myMock verify];
}
}
Run Code Online (Sandbox Code Playgroud)
我有一种感觉,在这两种情况下我都可能有点不合适:(
我真的很感激这方面的一些帮助.
谢谢.
更新1:
以下是我现在提出的内容,但需要知道我是在正确的轨道上还是犯了错误?
id mockSession = [OCMockObject mockForClass:[NSURLSession class]];
id mockDataTask = [OCMockObject mockForClass:[NSURLSessionDataTask class]];
[[mockSession stub] dataTaskWithRequest:OCMOCK_ANY
completionHandler:^(NSData _Nullable data, NSURLResponse Nullable response, NSError * Nullable error)
{
NSLog(@"Response: %@", response);
}];
[[mockDataTask stub] andDo:^(NSInvocation *invocation)
{
NSLog(@"invocation: %@", invocation);
}];
Run Code Online (Sandbox Code Playgroud)
块的技巧是您需要测试来调用块,并使用测试想要的任何参数。
\n\n在 OCMock 中,可以这样完成:
\n\nOCMStub([mock someMethodWithBlock:([OCMArg invokeBlockWithArgs:@"First arg", nil])]);\nRun Code Online (Sandbox Code Playgroud)\n\n这很方便。但是\xe2\x80\xa6\n
someMethodWithBlock:被调用时将立即被调用。这通常不反映生产代码的时间。\n\n如果您想推迟调用该块直到调用方法完成之后,则捕获它。在 OCMock 中,可以这样完成:
\n\n__block void (^capturedBlock)(id arg1);\nOCMStub([mock someMethodWithBlock:[OCMArg checkWithBlock:^BOOL(id obj) {\n capturedBlock = obj;\n return YES;\n}]]);\n\n// ...Invoke the method that calls someMethodWithBlock:, then...\ncapturedBlock(@"First arg"); // Call the block with whatever you need\nRun Code Online (Sandbox Code Playgroud)\n\n我更喜欢使用OCHamcrest'sHCArgumentCaptor。OCMock 支持 OCHamcrest 匹配器,所以我相信这应该有效:
\n\nHCArgumentCaptor *argument = [[HCArgumentCaptor alloc] init];\nOCMStub([mock someMethodWithBlock:argument]);\n\n// ...Invoke the method that calls someMethodWithBlock:, then...\nvoid (^capturedBlock)(id arg1) = argument.value; // Cast generic captured argument to specific type\ncapturedBlock(@"First arg"); // Call the block with whatever you need\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
1276 次 |
| 最近记录: |