我的视图控制器中有一个IBAction,看起来像这样
-(IBAction)signUpAction:(id)sender
{
AppDelegate *appDel = [[UIApplication sharedApplication]delegate];
//check for internet Connection
if(appDel.isReachable)
{
//Internet Connection available
//perform animation od buttons and imagie view
[self fallDownAnimation];
//after animation perform model segue to corresponding view controller
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.8f target:self selector:@selector(performRegistrationPageSegue) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
else
{
//No internet Connection
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_VIEW_TITLE message:@"No Internet Connection" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Okay", nil];
[alert show];
}
}
-(void)performRegistrationPageSegue{
[self performSegueWithIdentifier:@"registerVCSegue" sender:self];
}
我想在signUpAction方法上编写一个测试用例,并验证是否执行了Segue。由于它有一个计时器,我写的测试用例失败了。 我需要一种方法来测试以下条件
My Current Testcase方法
-(void)testRegisterViewControllerSegueOnAvailableInternetConnection{
AppDelegate *appDel = [[UIApplication sharedApplication]delegate];
appDel.isReachable = YES;
id loginMock = [OCMockObject partialMockForObject:_initialViewControllerToTest];
[[loginMock expect] performSegueWithIdentifier:@"registerVCSegue" sender:[OCMArg any]];
[loginMock performSelectorOnMainThread:@selector(signUpAction:) withObject:_initialViewControllerToTest.signUpButton waitUntilDone:YES];
XCTAssert([loginMock verify],@"Segue to Register Page not Performed on Sign Up Click");
}
答案 0 :(得分:1)
您需要输入一段时间的事件循环,以便可以处理计时器事件。如果不这样做,基本上不可能完全回归测试代码。这是一个简化的方法:
// Wait inside the event loop for a period of time indicated in seconds
+ (void) waitFor:(NSTimeInterval)maxWaitTime
{
int numSeconds = (int) round(maxWaitTime);
if (numSeconds < 1) {
numSeconds = 1;
}
for ( ; numSeconds > 0 ; numSeconds--) @autoreleasepool {
const int maxMS = 1000;
const int incrMS = 1;
const double seconds = 1.0 / (maxMS / incrMS);
for (int ms = 0 ; ms < maxMS; ms += incrMS) @autoreleasepool {
// One pass through the run loop for each time interval
NSDate *maxDate = [NSDate dateWithTimeIntervalSinceNow:seconds];
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:maxDate];
}
}
return;
}
带有选择器的更复杂的impl,可以在测试条件为真时调用它来返回:
+ (BOOL) waitUntilTrue:(id)object
selector:(SEL)selector
maxWaitTime:(NSTimeInterval)maxWaitTime
{
NSAssert(object, @"object is nil");
NSAssert(selector, @"selector is nil");
NSMethodSignature *aSignature = [[object class] instanceMethodSignatureForSelector:selector];
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[anInvocation setSelector:selector];
[anInvocation setTarget:object];
// Invoke test condition method once before the timing loop is entered, so that the
// event loop will not be entered if the condition is initially TRUE.
BOOL state;
[anInvocation invoke];
[anInvocation getReturnValue:&state];
if (state) {
return TRUE;
}
// The condition is FALSE, so enter the event loop and wait for 1 second
// each iteration through the loop. The logic below makes sure that the
// 1 second wait will be done at least once, even if wait time is less
// than a full second.
int numSeconds = (int) round(maxWaitTime);
if (numSeconds < 1) {
numSeconds = 1;
}
for ( ; numSeconds > 0 ; numSeconds--) @autoreleasepool {
NSDate *maxDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
[[NSRunLoop currentRunLoop] runUntilDate:maxDate];
[anInvocation invoke];
[anInvocation getReturnValue:&state];
if (state) {
return TRUE;
}
}
return FALSE;
}