0

I'm using Kiwi to do some asynchronous testing. One test checks that, after a (stubbed) network request, the response from the network is written to disk. Both the network request and writing the response to disk are done on background queues:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    [[HZMediationAPIClient sharedClient] GET:@"start" parameters:nil success:^(HZAFHTTPRequestOperation *operation, NSDictionary *json) {

        // store JSON to disk
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            [json writeToURL:[[self class] pathToStartInfo] atomically:YES];
        });

        [self.delegate startWithDictionary:json fromCache:NO];

    } failure:^(HZAFHTTPRequestOperation *operation, NSError *error) {

    }];
});

I can test things like the delegate receiving the startWithDicationary:fromCache method using Kiwi's asynchronous testing capabilities:

[[expectFutureValue(starterMock) shouldEventually] receive:@selector(startWithDictionary:fromCache:) withArguments:json,theValue(NO)];

However, I'm not sure how to test that the data is written to disk correctly. I can do something like send a delegate method when after the data is written to disk, and then test that that happens:

[[expectFutureValue(starterMock) shouldEventually] receive:@selector(wroteDictionaryToCache)];

But even if I verify that message is sent, I can't check that the data is actually written to disk.

it(@"Returns the data from network when no cached value, then updates the cache", ^{
    // ... test setup here

    [[expectFutureValue(starterMock) shouldEventually] receive:@selector(wroteDictionaryToCache)]; // This code finishes immediately
    // Code here checking if the data has been written to disk will be executed before the above expectations become true.
});

Is there a way I can wait for the asynchronous expectations to pass/fail, so that I can then test that the data is written to disk? Or can I attach a completion block to the expectations, so that I can write future tests when those async expectations pass/fail?

If you have an alternative approach to testing this, that would be good as well.

MaxGabriel
  • 7,617
  • 4
  • 35
  • 82

1 Answers1

0

I didn't come up with a way to accomplish exactly this, but I concluded it was better for testing purposes to move the caching logic out into a separate object and make it a dependency for the class I was testing. The interface for that looks like this:

@interface HZCachingService : NSObject

- (void)cacheDictionary:(NSDictionary *)dictionary filename:(NSString *)filename;
- (NSDictionary *)dictionaryWithFilename:(NSString *)filename;

@end

I just pass that object to the class I'm testing in its init method. In the tests, I stub that object and verify that cacheDictionary:filename: is called on it with the correct arguments.

I test the actual writing-to-disk behavior of HZCachingService in a separate spec.

MaxGabriel
  • 7,617
  • 4
  • 35
  • 82