8

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?

Santiago Alessandri
  • 6,630
  • 30
  • 46
Chris Marshall
  • 4,910
  • 8
  • 47
  • 72
  • 1
    Does this thread help? http://stackoverflow.com/questions/12463733/objective-c-unit-testing-dispatch-async-block – Guy Kogus Oct 22 '13 at 16:26

2 Answers2

10

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/

Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
1

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
}
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421