我遇到了 XCTestCase 对象中的异步操作问题。我从一个链开始expectation-waitForExpectation
,有时将期望实例作为方法参数传递,以使其由异步操作完成块来实现。现在我改变了方法,因为我看不到以前写的不好的代码,所以我尝试了这种方式:
- (void)testThatItGoesToTheRightSport
{
if (! appDelegateInstance.firstTimeLoaded)
{
[self __waitForLoadingAppAndDo:^(BOOL launched)
{
if (launched)
{
[self __goToLiveWithHandler:^(BOOL success) {
if (success)
{
[self __goToLiveSport:[NSNumber numberWithUnsignedInteger:kDefaultSportCode]
handler:^(BOOL success) {
if (! success)
{
XCTFail(@"Test failed");
}
}];
}
}];
}
}];
}
else
{
[self __goToLiveWithHandler:^(BOOL success) {
if (success)
{
[self __goToLiveSport:[NSNumber numberWithUnsignedInteger:kDefaultSportCode]
handler:^(BOOL success) {
if (! success)
{
XCTFail(@"Test failed");
}
}];
}
}];
}
}
__waitForLoadingAppAndDo:
方法实现为
- (void)__waitForLoadingAppAndDo:(void (^)(BOOL launched))afterBlock
{
if (! afterBlock)
XCTFail(@"No afterBlock");
XCTestExpectation *dataEx = [self expectationForNotification:NOTIFICATION_HOME_LOADED
object:nil
handler:^BOOL(NSNotification *notification) {
[dataEx fulfill];
return YES;
}];
[self waitForExpectationsWithTimeout:SOCKOPT_TIMEOUT handler:^(NSError *error)
{
if (error)
{
XCTFail(@"No data received. %@", [error localizedDescription]);
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
afterBlock(YES);
});
}
}];
}
其他__
方法与此类似。显然,现在,该testThat
方法不等待方法完成处理程序。我该如何改进它以及如何让testThat
方法等待完成?是XCTestExpectation
路吗?(告诉我不要呃)
补充:那么,这是独特的方式吗?
- (void)testThatItGoesToTheRightSport
{
if (! appDelegateInstance.firstTimeLoaded)
{
XCTestExpectation *waitingLoading = [self expectationWithDescription:@"loadingApp"];
[self waitForExpectationsWithTimeout:SOCKOPT_TIMEOUT handler:^(NSError *error) {
if (error)
{
XCTFail(@"After block was not called.");
}
}];
[self __waitForLoadingAppAndDo:^(BOOL launched)
{
if (launched)
{
[self __goToLiveWithHandler:^(BOOL success) {
if (success)
{
[waitingLoading fulfill];
[...]
}
}];
}
}];
添加-2:
我试过了
__block NSError *internalError = nil;
__block XCTestExpectation *finishedTest = [self expectationWithDescription:@"finishedTest"];
dispatch_group_t asyncGroup = dispatch_group_create();
if (! appDelegateInstance.firstTimeLoaded)
{
dispatch_group_enter(asyncGroup);
[self __waitForLoadingAppAndDo:^(BOOL launched) {
if (! launched)
{
internalError = [TestUtilities notLoadedAppError];
}
dispatch_group_leave(asyncGroup);
}];
dispatch_group_enter(asyncGroup);
[self __goToLiveWithHandler:^(BOOL success) {
if (! success)
{
internalError = [NSError errorWithDomain:@"goLive"
code:-1
userInfo:@{NSLocalizedDescriptionKey : @"Errore apertura Live"}];
}
dispatch_group_leave(asyncGroup);
}];
dispatch_group_notify(asyncGroup, dispatch_get_main_queue(), ^{
[finishedTest fulfill];
});
但是这些组被异步调用,无需等待完成块。例如:我期望OP1首先启动,并且在OP1完成块中, OP2将启动。
ADDING-3:我对dispatch_semaphore
. 我喜欢它,但有一个东西我会替换。如果我要等待信号,我会阻塞主线程,所以我必须执行dispatch_async
以下wait
命令:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
dispatch_semaphore_wait(loadedApp, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
[self __goToLiveWithHandler:^(BOOL success) {
if (success)
{
[...]
}
}];
});
});
有没有办法避免这种情况?