1

I'm trying to test an API I'm writing with Structured Concurrency. I prefer to run my tests with continueAfterFailure = false so that I may establish preconditions on my tests. At the moment my test is:

func testRssUrl() async throws {
    self.continueAfterFailure = false // 1
    let xml = PodcastXml.url(url)
    let feed = try await xml.feed // 2
    let rssFeed: RSSFeed? = feed.rssFeed
    XCTAssertNil(rssFeed) // 3 Included for this example
    XCTAssertNotNil(rssFeed) // 4
    validate(zebraFeed: rssFeed!) // 5
}

My expectation of Swift Concurrency is that the try await (2) should hold the method, until the expression resolves to a value or the expression throws. Either of the XCTAssertNil (3) or XCTAssertNotNil (4) should fail (in the actual test, I'm only using XCTAssertNotNil).

As written, between the two asserts and the try, validate(zebraFeed:) (5) should never be called because of continueAfterFailure (1). Yet it is. The test still fails because XCTAssertNil (3) is failing, which is my actual expectation, but the test execution should also be stopping there.

What am I missing?

====Update======

Following replies I have an expanded example:

class TestAwaitTests: XCTestCase {

    struct Thing {
        let value = true
        func doSomething() async throws -> Int? {
            try await Task.sleep(nanoseconds: 5_000_000_000)
            return 1
        }
    }

    func validation(thing: Thing, file: StaticString = #file, line: UInt = #line) {
        XCTAssertFalse(thing.value)
        XCTAssertTrue(thing.value) // Breakpoint here
    }

    func testTest() async throws {
        continueAfterFailure = false
        let thing = Thing()
        let result = try await thing.doSomething()
        print("print 1")
        XCTAssertNil(result)
        print("print 2")
        XCTAssertNotNil(result)
        print("print 3")
        validation(thing: thing)
        enum Err: Error { case oops }
        throw Err.oops
        print("print 4")
    }
}

With console output:

print 1
print 2
print 3

The test fails, as expected. What is unexpected is that the statements print 2 and print 3 are produced. continueAfterFailure should be stopping the test first assertion.

===Update 2===

The second case had been updated with a validate(thing:) method. With continueAfterFailure set to false, the line marked Breakpoint here should never execute.

0 Answers0