Delayed OCMock verify / Dealing with Timeout in Unit Tests
Asked Answered
E

3

7

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?

Excitability answered 5/9, 2011 at 16:12 Comment(0)
N
7

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.

Nyaya answered 6/9, 2011 at 2:21 Comment(2)
Perhaps originated here?... touchalicious.com/blog/2009/11/5/…Parted
Thanks Max - that looks like the source. I've updated the original response with a link to the original.Nyaya
A
1

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.

Angers answered 6/9, 2011 at 7:1 Comment(1)
I already have canned tests with immediate fake returns from the web service. This question was about integration tests with the real web service. I admit that I could leave the application part aside in those, but it does not change the fact that I need to wait for the result somehow. And: with the canned results, I don't test having a latency between request and result, as with canned results, the result delegate actually is called before the request call is finished.Excitability
V
0

You could also switch to GHUnit, like a fellow member suggests in the answer to this related question:

SenTestingKit in Xcode 4: Asynchronous testing?

You can find GHUnit here

https://github.com/gabriel/gh-unit

Venitavenite answered 10/5, 2012 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.