我正在努力找出在后台线程中测试与 Core Data 交互的最佳方法。我有以下类方法:
+ (void)fetchSomeJSON
{
// Download some json then parse it in the block
[[AFHTTPClient sharedClient] fetchAllThingsWithCompletion:^(id results, NSError *error) {
if ([results count] > 0) {
NSManagedObjectContext *backgroundContext = //... create a new context for background insertion
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(background, ^{ // If I comment this out, my test runs just fine
//... insert and update some entities
for (NSString *str in results) {
NSManagedObject *object = //...
}
});
}
}];
}
我目前正在使用以下 Kiwi 代码测试此方法:
describe(@"MyAction", ^{
__block void (^completionBlock)(NSArray *array, NSError *error);
beforeEach(^{
// Stub the http client
id mockClient = [AFHTTPClient mock];
[WRNAPIClient stub:@selector(sharedClient) andReturn:mockClient];
// capture the block argument
KWCaptureSpy *spy = [mockClient captureArgument:@selector(fetchAllThingsWithCompletion:) atIndex:0];
[MyClass fetchSomeJSON]; // Call the method so we can capture the block
completionBlock = spy.argument;
// run the completion block
completionBlock(@[@"blah"], nil);
})
// If I remove the dispatch_async block, this test passes fine.
// If I add it in again the test fails, probably because its not waiting
it(@"should return the right count", ^{
// entityCount is a block that performs a fetch request count
NSInteger count = entityCount(moc, @"Task");
[[theValue(count) should] equal:theValue(4)];
})
// This works fine, but obviously I don't want to wait a second
it(@"should return the right count after waiting for a second", ^{
sleep(1);
NSInteger count = entityCount(moc, @"Task");
[[theValue(count) should] equal:theValue(4)];
});
};
如果我删除该dispatch_async
行,那么我可以让我的测试快速运行。我可以让我的测试套件在使用时运行的唯一方法dispatch_async
是sleep(1)
在调用完成块之后。使用sleep()
让我认为我没有以正确的方式接近它。我试过使用shouldEventually
,但这似乎并没有重新获取我的count
价值。