Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS -NSRunLoop in XCTest: How Do I Get A Run Loop to Work in A Unit Test?

OK. I looked around, and didn't find an exact answer to my issue.

I am trying to test a timeout handler in a unit test (not the main run).

The issue seems to be that the [NSRunLoop mainRunLoop] is not running in unit tests the way it does in the standard Run.

I do my timeouts in this manner:

NSTimer *pTimeoutHandler = [NSTimer 
    timerWithTimeInterval:2.0 
    target:self 
    selector:@selector(timeoutHandler:) 
    userInfo:nil 
    repeats:NO
];
[[NSRunLoop mainRunLoop] addTimer:pTimeoutHandler forMode:NSRunLoopCommonModes];

This works in the standard run. This is the recommended manner of setting a timeout.

However, in the Test run, this doesn't work. The timeoutHandler:(NSTimer*)timer routine is never called.

It appears as if something is interfering with the run loop.

Is there any way for me to get the timeout to work in both run and unit test?

like image 233
Chris Marshall Avatar asked Oct 22 '13 16:10

Chris Marshall


2 Answers

When you use timers and the main runloop, you will need to manually run the runloop:

while (continueCondition || !time_way_over_timeout)  {
    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}

where continueConditioncould be some flag that indicates that the timeout handler was invoked and time_way_over_timeouta comparision of the current time with a pre-calulated maximum execution time (so you can handle a "timeout of timout test" for your unit test ^^)

Also see this blog post about asynchronous unit testing: http://dadabeatnik.wordpress.com/2013/09/12/xcode-and-asynchronous-unit-testing/

like image 106
Martin Ullrich Avatar answered Oct 25 '22 16:10

Martin Ullrich


Looks something like this in Swift 3.0 with XCTest.

// somebody has to call the .fulfill() method on this variable 
// to the expectation will fail after 25 seconds
var asyncExpectation : XCTestExpectation!

func testExample() {
    asyncExpectation = expectation(description: "longRunningFunction")
    self.waitForExpectations(timeout: 25.0) { (error) in
        if let error = error {
            print("Error \(error)")
        }
    }
    // more stuff here
}
like image 33
Dan Rosenstark Avatar answered Oct 25 '22 16:10

Dan Rosenstark