使用 XCTestExpectation 单元测试异步函数,但它不会等待我设置的秒数
unit test async function by using XCTestExpectation but it doesn't wait for the seconds I set
我有一个 MyService
class 继承了 NSThread
:
header:
@interface MyService : NSThread {
-(void) startMe;
-(void) doTask;
...
}
实施:
@implementation MyService
-(void)startMe {
[self start];
}
-(void) doTask {
[self performSelector:@selector(checkData:) onThread:self withObject:nil waitUntilDone:YES];
}
-(void) checkData {
...
// NOTE: dataChecked is an instance variable.
dataChecked = YES;
}
@end
我想对上面的 -(void)doTask
进行单元测试并验证 -(void)checkData
是否真的被调用了。我使用 OCMock library 来部分模拟 MyService
。
受到this tutorial (use XCTestExpectation)的启发,我尝试了以下方法:
-(void) testCheckData {
// partial mock MyService
id myService = [OCMockObject partialMockForObject:[MyService getInstance]];
[myService startMe];
// function to test
[myService doTask];
// I setup expectation
XCTestExpectation *expectation = [self expectationWithDescription:@"data checked"];
// run assertion asynchronisely
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
XCTAssertTrue([self isDataChecked]);
// expectation fulfill
[expectation fulfill];
});
// wait for 5 seconds
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if (error) {
NSLog(@"Timeout Error: %@", error);
}
}];
}
然而,当我 运行 我的测试时,waitForExpectationsWithTimeout:handler: 不起作用,我的意思是它不会等待 5 秒,断言部分 运行 紧随功能之后在测试中被调用。为什么它不等待 5 秒?
======更新======
我也试过不使用异步块:
-(void) testCheckData {
// partial mock MyService
id myService = [OCMockObject partialMockForObject:[MyService getInstance]];
[myService startMe];
// function to test
[myService doTask];
// I setup expectation
XCTestExpectation *expectation = [self expectationWithDescription:@"data checked"];
// run assertion
XCTAssertTrue([self isDataChecked]);
// expectation fulfill
[expectation fulfill];
// wait for 5 seconds
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if (error) {
NSLog(@"Timeout Error: %@", error);
}
}];
}
但是我还是遇到同样的问题,没有等待5秒,立即测试return,为什么?
===== 和 =====
如果我们忽略我上面的更新并返回查看我的原始代码使用异步块,我可能会抱怨。我认为 waitForExpectations:5
应该等待我不需要使用 while
循环,为什么我认为这种方式是因为 tutorial.
如果我们查看那个教程,它首先显示 使用 while 循环 等待的旧样式,然后,它更改为 不会等待的期望样式使用任何while循环,它所做的是设置期望->开始工作(在其工作的完成块中断言),它还有waitForExpectations:
代码,看起来和我的代码完全一样使用异步块。我想了解为什么我的原始代码看起来与教程相同但不起作用。我错过了什么吗?
一旦您开始 waitForExpectations,您的 dispatch_async 就有机会 运行。它会断言您的数据已经过检查,然后——无论您的数据是否已经过检查——它都会将预期标记为已实现。一旦完成,我们不再需要等待,我们可以完成。
这可能不是您想做的,但代码就是这么说的。
好的,解决了。
我应该使用 dispatch_after
而不是 dispatch_async
,因为我的被测函数中没有完成块,而该教程中的示例有一个。所以,我需要改成这样:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
XCTAssert(...);
[expectation fulfill];
});
如果你想使用dispatch_async
请查看@Avi的评论,在异步块中使用while
循环等待。
我有一个 MyService
class 继承了 NSThread
:
header:
@interface MyService : NSThread {
-(void) startMe;
-(void) doTask;
...
}
实施:
@implementation MyService
-(void)startMe {
[self start];
}
-(void) doTask {
[self performSelector:@selector(checkData:) onThread:self withObject:nil waitUntilDone:YES];
}
-(void) checkData {
...
// NOTE: dataChecked is an instance variable.
dataChecked = YES;
}
@end
我想对上面的 -(void)doTask
进行单元测试并验证 -(void)checkData
是否真的被调用了。我使用 OCMock library 来部分模拟 MyService
。
受到this tutorial (use XCTestExpectation)的启发,我尝试了以下方法:
-(void) testCheckData {
// partial mock MyService
id myService = [OCMockObject partialMockForObject:[MyService getInstance]];
[myService startMe];
// function to test
[myService doTask];
// I setup expectation
XCTestExpectation *expectation = [self expectationWithDescription:@"data checked"];
// run assertion asynchronisely
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
XCTAssertTrue([self isDataChecked]);
// expectation fulfill
[expectation fulfill];
});
// wait for 5 seconds
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if (error) {
NSLog(@"Timeout Error: %@", error);
}
}];
}
然而,当我 运行 我的测试时,waitForExpectationsWithTimeout:handler: 不起作用,我的意思是它不会等待 5 秒,断言部分 运行 紧随功能之后在测试中被调用。为什么它不等待 5 秒?
======更新======
我也试过不使用异步块:
-(void) testCheckData {
// partial mock MyService
id myService = [OCMockObject partialMockForObject:[MyService getInstance]];
[myService startMe];
// function to test
[myService doTask];
// I setup expectation
XCTestExpectation *expectation = [self expectationWithDescription:@"data checked"];
// run assertion
XCTAssertTrue([self isDataChecked]);
// expectation fulfill
[expectation fulfill];
// wait for 5 seconds
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if (error) {
NSLog(@"Timeout Error: %@", error);
}
}];
}
但是我还是遇到同样的问题,没有等待5秒,立即测试return,为什么?
===== 和 =====
如果我们忽略我上面的更新并返回查看我的原始代码使用异步块,我可能会抱怨。我认为 waitForExpectations:5
应该等待我不需要使用 while
循环,为什么我认为这种方式是因为 tutorial.
如果我们查看那个教程,它首先显示 使用 while 循环 等待的旧样式,然后,它更改为 不会等待的期望样式使用任何while循环,它所做的是设置期望->开始工作(在其工作的完成块中断言),它还有waitForExpectations:
代码,看起来和我的代码完全一样使用异步块。我想了解为什么我的原始代码看起来与教程相同但不起作用。我错过了什么吗?
一旦您开始 waitForExpectations,您的 dispatch_async 就有机会 运行。它会断言您的数据已经过检查,然后——无论您的数据是否已经过检查——它都会将预期标记为已实现。一旦完成,我们不再需要等待,我们可以完成。
这可能不是您想做的,但代码就是这么说的。
好的,解决了。
我应该使用 dispatch_after
而不是 dispatch_async
,因为我的被测函数中没有完成块,而该教程中的示例有一个。所以,我需要改成这样:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
XCTAssert(...);
[expectation fulfill];
});
如果你想使用dispatch_async
请查看@Avi的评论,在异步块中使用while
循环等待。