Chris Marshall
Chris Marshall

Reputation: 5332

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?

Upvotes: 8

Views: 6540

Answers (2)

Dan Rosenstark
Dan Rosenstark

Reputation: 69787

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
}

Upvotes: 1

Martin Ullrich
Martin Ullrich

Reputation: 100761

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/

Upvotes: 10

Related Questions