XCTest Assert Expectation wasn't fulfilled

4.5k views Asked by At

When writing a certain asynchronous test using XCTest and XCTestExpectation I would like to assert that a certain block was not executed. The following code is successful in asserting that a block was executed and if not the test fails.

#import <XCTest/XCTest.h>
#import "Example.h"

@interface Example_Test : XCTestCase

@property (nonatomic) Example *example;

@end

@implementation Example_Test
- (void)setUp {
    [super setUp];
}

- (void)tearDown {
     [super tearDown];
}

- (void)testExampleWithCompletion {
    self.example = [[Example alloc] init];
    XCTestExpectation *expectation = [self expectationWithDescription:@"expection needs to be fulfilled"];
    [self.example exampleWithCompletion:^{
        [expectation fulfill]
    }];
    [self waitForExpectationsWithTimeout:2.0 handler:^(NSError *error) {
        if (error) {
            NSLog(@"Timeout Error: %@", error);
        }
    }];
}

There doesn't seem to be an obvious way to execute this the other way around; where the test succeeds if the block did not execute after the timeout and fails if it executed before the timeout. Adding to this, I would like to assert that the block executed at a later time when a different condition is met.

Is there a straightforward way to do this with XCTestExpectation or will I have to create a workaround?

2

There are 2 answers

0
txDecompression On

I know this is a couple years old, but I just stumbled across a parameter on XCTestExpectation that lets you invert the expectation. Hopefully this will help someone else stumbling across this. Answer is in Swift

let expectation = XCTestExpectation(description: "")
expectation.isInverted = true

Documentation: https://developer.apple.com/documentation/xctest/xctestexpectation/2806573-isinverted

0
Ric Santos On

You can achieve this with a dispatch_after call that is scheduled to run just before your timeout. Use a BOOL to record if the block has executed, and an assertion to pass or fail the test once the expectation is completed.

- (void)testExampleWithCompletion {
    self.example = [[Example alloc] init];
    __block BOOL completed = NO;
    [self.example exampleWithCompletion:^{
        completed = YES;
    }];

    XCTestExpectation *expectation = [self expectationWithDescription:@"expection needs to be fulfilled"];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [expectation fulfill];
    });
    [self waitForExpectationsWithTimeout:3.0 handler:nil];

    XCTAssertEqual(completed, NO);
}