Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delayed OCMock verify / Dealing with Timeout in Unit Tests

I'm testing real web service calls with OCMock.

Right now I'm doing something like:

- (void)testWebservice
{
    id mydelegatemock = [OCMockObject mockForProtocol:@protocol(MySUTDelegate)];
    [[mydelegatemock expect] someMethod:[OCMArg any]];

    [SUT sutWithDelegate:mydelegatemock];

    // we need to wait for real result
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

    [(OCMockObject*)mydelegatemock verify];
}

It works fine, but it implies that every such test will take 2 seconds.

Is there a way I can set a timeout of e.g. 2 seconds, and let a call to someMethod of mydelegatemock immediately verify and complete the test case?

like image 317
fabb Avatar asked Sep 05 '11 16:09

fabb


2 Answers

I do this using a handy utility function I found at this link:

#import <Foundation/Foundation.h>
#import <OCMock/OCMock.h>

@interface TestUtils : NSObject
+ (void)waitForVerifiedMock:(OCMockObject *)mock delay:(NSTimeInterval)delay;
@end

And the implementation:

#import "TestUtils.h"
@implementation TestUtils

+ (void)waitForVerifiedMock:(OCMockObject *)inMock delay:(NSTimeInterval)inDelay
{
    NSTimeInterval i = 0;
    while (i < inDelay)
    {
        @try
        {
            [inMock verify];
            return;
        }
        @catch (NSException *e) {}
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
        i+=0.5;
    }
    [inMock verify];
}

@end

This allows me to to wait up to a maximum delay (in seconds) without waiting the full amount each time.

like image 195
Tim Dean Avatar answered Oct 20 '22 15:10

Tim Dean


I would separate the functional testing of your web services (if you need to do that at all) from the unit testing of your class that processes the web service result.

To unit test, you should mock the web service call, providing a mock result. Then your test would verify that, for that well-defined result, your class behaves accordingly.

If you also want to do functional testing of your web service (say that it returns a specific response given some request), you don't need to mock anything--just call the service and make assertions on the result.

By separating out your tests, you have finer control over the test runs. For example, you could run your fast-running unit tests every time you change code, but run your slow-running functional tests nightly, on a dedicated server, or as needed. And when a test breaks, you'll know whether it's your code or something wrong with the web service.

like image 1
Christopher Pickslay Avatar answered Oct 20 '22 16:10

Christopher Pickslay