Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Testing a delegate is trivial. Just set an ivar in the test in your callback method, and check it after what should be triggering the delegate callback.</p> <p>For example, if I have a class <code>Something</code> that uses a delegate of protocol <code>SomethingDelegate</code> and sends that delegate <code>-something:delegateInvoked:</code> in response to some message, I can test it lik ethis:</p> <pre><code>@interface TestSomeBehavior : SenTestCase &lt;SomethingDelegate&gt; { Something *_object; BOOL _callbackInvoked; } @end @implementation TestSomeBehavior - (void)setUp { [super setUp]; _object = [[Something alloc] init]; _object.delegate = self; } - (void)tearDown { _object.delegate = nil; [_object release]; [super tearDown]; } - (void)testSomeBehaviorCallingBack { [_object doSomethingThatShouldCallBack]; STAssertTrue(_callbackInvoked, @"Delegate should send -something:delegateInvoked:"); } - (void)something:(Something *)something delegateInvoked:(BOOL)invoked { _callbackInvoked = YES; } @end </code></pre> <p>I think you already understand this, however, from the way you've phrased your question. (I'm mostly posting this for other readers.) I think you're actually asking a more subtle question: How do I test something that <strong>may occur later</strong> such as something that spins the runloop. My cue is your mention of sleeping and threading.</p> <p>First off, you <strong>should not</strong> just arbitrarily invoke a method on another thread. You should only do so if it's documented to be safe to use in that way. The reason is that you don't know what the internals of the class do. For example, it might schedule events on the run loop, in which case running the method on a different thread will make them happen on a different run loop. This would then screw up the class's internal state.</p> <p>If you <strong>do</strong> need to test something that may take a little time to happen, you can do this just by running the current run loop. Here's how I might rewrite the individual test method above to do that:</p> <pre><code>- (void)testSomeBehaviorCallingBack { NSDate *fiveSecondsFromNow = [NSDate dateWithTimeIntervalSinceNow:5.0]; [_object doSomethingThatShouldCallBack]; [[NSRunLoop currentRunLoop] runUntilDate:fiveSecondsFromNow]; STAssertTrue(_callbackInvoked, @"Delegate should send -something:delegateInvoked:"); } </code></pre> <p>This will spin the current run loop in the default mode for 5 seconds, under the assumption that <code>-doSomethingThatShouldCallBack</code> will schedule its work on the main run loop in the default mode. This is usually OK because APIs that work this way often let you specify a run loop to use as well as a mode to run in. If you can do that, then you can use <code>-[NSRunLoop runMode:beforeDate:]</code> to run the run loop in just that mode instead, making it more likely that the work you're expecting to be done will be.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload