更正 timing/placement 的 XCTestExpectation fulfill 单元测试中的方法调用?

Correct timing/placement of XCTestExpectation fulfill method call in unit tests?

考虑以下单元测试:

- (void)testSample {
    XCTestExpectation *expectation = [self expectationWithDescription:@"Sample"];

    [self.manager loadAllSuccess:^{
        [expectation fulfill];

        NSArray *data = [self.manager dataForIndex:0];

        // Correct count of data is 10, not 44 - this should fail.
        XCTAssertEqual(44, data.count);
    } failure:^(NSError *error) {
        [expectation fulfill];

        XCTFail(@"Error encountered");
    }];

    [self waitForExpectationsWithTimeout:60 handler:nil];
}

我在已知失败案例中遇到了一些问题。尽管数据数组中应该只有 10 个项目,但测试成功完成。

如果我将 [expectation fulfill] 调用放在块的底部,在 XCTAssertEqual(44, data.count) 方法调用之后,测试会按预期工作并失败,直到我将值更正为 10。

这是一个已知问题吗?我一直无法阅读说明我应该在最后一刻调用它的文档...

根据http://nshipster.com/xctestcase/

Always call fulfill() at the end of the asynchronous callback—fulfilling the expectation earlier can set up a race condition where the run loop may exit before completing the test. If the test has more than one expectation, it will not pass unless each expectation executes fulfill() within the timeout specified in waitForExpectationsWithTimeout().

刚找到这个 - 不确定它是否 100% 准确,因为我在其他地方看不到任何其他说明这一点的文档。

是的,您应该只在您的期望得到满足时才致电 fulfill。如果您希望您的断言在测试结束前就已执行,则必须在断言执行后才满足您的期望。

正如@Zach 的回答所述,引用 NSHipster,测试完全有可能在 success/failure 块完成之前停止执行,因为测试唯一等待的是要实现的期望。成功和失败块在不知道测试的情况下执行。一旦达到预期,测试执行就会停止,任何进一步的代码都不会被执行。

你的代码在成功和失败的情况下都达到了预期,所以无论结果如何,似乎这个测试都会通过。我建议您将可以实现期望的地方的数量限制在一个地方,这样您就可以在测试通过时知道什么在工作,在失败时知道什么在失败,而无需进一步调试。您应该将此测试分成两部分,其中一个在成功块而不是失败块中满足期望,在第二个测试中反之亦然。