Skip to content

[SR-12575] Over-fulfilling XCTestExpectation records test failure even when assertForOverFulfill is disabled #320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

stmontgomery
Copy link
Contributor

This fixes an issue where calling XCTestExpectation.fulfill() more times than expected will still
record a test failure, even if its assertForOverFulfill property is set to false (the default).
In this Corelibs version of XCTest, assertForOverFulfill is only guarding a fatalError, but we
still unconditionally record a test failure which causes this symptom. This means the behavior is
different than in the Xcode copy of XCTest, where if assertForOverFulfill is false, neither an
NSAssert exception nor a test failure occurs. Swift doesn't support exceptions, so I believe the
unconditional test failure was added here in the past in an attempt to emulate that behavior.

The fix here removes the fatalError() entirely, and leaves the test failure-recording logic but
makes it conditional on assertForOverFulfill being true. The behavior will still differ from Xcode's
copy of XCTest, but I think it's justifiable and closer to what users expect. The use of NSAssert in
the (ObjC) Xcode copy of XCTest was largely an attempt to get better diagnostics when an over-fulfill
occurred by capturing the backtrace of that fulfillment. This is especially important with
XCTestExpectations, since they are meant for testing async conditions, and an over-fulfillment could
occur after their test has completed, so without a backtrace or some better state tracking the test
failure could be misattributed to a subsequent test once it becomes "current". Corelibs XCTest doesn't
suffer from this diagnostics problem as much since it already captures file:line: in fulfill().
Moreover, there have been requests to change that behavior in ObjC XCTest and use a "plain" test failure
everywhere instead of NSAssert.

So this PR gets us closer to that goal, starting here in Corelibs, by removing the fatalError and only
leaving the existing test failure-recording behavior. To fully realize it and ensure these test
failures are attributed to the correct test, we'll need to make further internal state tracking
enhancements (63874139), but for now this seems like a good incremental step, considering that Corelibs
already performed this test failure recording. I've also added a new test and modified an existing one.

rdar://problem/62202297

…ertForOverFulfill` is disabled

This fixes an issue where calling `XCTestExpectation.fulfill()` more times than expected will still
record a test failure, even if its `assertForOverFulfill` property is set to `false` (the default).
In this Corelibs version of XCTest, `assertForOverFulfill` is only guarding a `fatalError`, but we
still unconditionally record a test failure which causes this symptom. This means the behavior is
different than in the Xcode copy of XCTest, where if `assertForOverFulfill` is false, neither an
NSAssert exception nor a test failure occurs. Swift doesn't support exceptions, so I believe the
unconditional test failure was added here in the past in an attempt to emulate that behavior.

The fix here removes the `fatalError()` entirely, and leaves the test failure-recording logic but
makes it conditional on `assertForOverFulfill` being true. The behavior will still differ from Xcode's
copy of XCTest, but I think it's justifiable and closer to what users expect. The use of NSAssert in
the (ObjC) Xcode copy of XCTest was largely an attempt to get better diagnostics when an over-fulfill
occurred by capturing the backtrace of that fulfillment. This is especially important with
XCTestExpectations, since they are meant for testing async conditions, and an over-fulfillment could
occur after their test has completed, so without a backtrace or some better state tracking the test
failure could be misattributed to a subsequent test once it becomes "current". Corelibs XCTest doesn't
suffer from this diagnostics problem as much since it already captures `file:line:` in `fulfill()`.
Moreover, there have been requests to change that behavior in ObjC XCTest and use a "plain" test failure
everywhere instead of NSAssert.

So this PR gets us closer to that goal, starting here in Corelibs, by removing the fatalError and only
leaving the existing test failure-recording behavior. To fully realize it and ensure these test
failures are attributed to the correct test, we'll need to make further internal state tracking
enhancements (63874139), but for now this seems like a good incremental step, considering that Corelibs
already performed this test failure recording. I've also added a new test and modified an existing one.

rdar://problem/62202297
@stmontgomery
Copy link
Contributor Author

@swift-ci please test

@stmontgomery stmontgomery changed the title Over-fulfilling XCTestExpectation records test failure even when assertForOverFulfill is disabled [SR-12575] Over-fulfilling XCTestExpectation records test failure even when assertForOverFulfill is disabled Nov 24, 2020
Copy link
Contributor

@briancroom briancroom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thanks for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants