mercredi 22 juillet 2020

How to know XCTestExpectation 'expectedFulfillmentCount'

In async tests is common, at least for me, to have to know the fulfilment count of an expectation to know how to assert.

For instance, a test to check this scenario:

  1. Fetch data
  2. After receiving first callback, assert if items are as expected
  3. Fetch next page of items
  4. Assert if items are as expected
    func testOne() {
        let expectData = expectation(description: "data")
        expectData.expectedFulfillmentCount = 2
        var expectDataFulfillmentCount = 0
        
        sut.data = {
            expectData.fulfill()
            expectDataFulfillmentCount += 1
            
            if expectDataFulfillmentCount == 1 {
                XCTAssertEqual(sut.numberOfItems, 3)
                sut.fetchNextPage()
            } else if expectDataFulfillmentCount == 2 {
                XCTAssertEqual(sut.numberOfItems, 6)
            }
        }

        sut.fetch()

        waitForExpectations(timeout: 0.1, handler: nil)
    }

I am not happy with this pattern. I know I can slightly change how I assert when having expectations, this way:

    func testTwo() {
        let expectFirstData = expectation(description: "firstData")
        let expectSecondData = expectation(description: "secondData")
        
        sut.data = {
            if sut.numberOfItems == 3 {
                expectFirstData.fulfill()
                sut.fetchNextPage()
            } else if sut.numberOfItems == 6 {
                expectSecondData.fulfill()
            }
        }

        sut.fetch()

        wait(for: [expectFirstData, expectSecondData], timeout: 0.1, enforceOrder: true)
    }

But I don't like this neither because then I am not asserting (there is no XCTAssert), I am just fulfilling expectations and then loosing the capacity to easily identify why and where the test failed. This pattern, though, is perfect for expectations over boolean values, like this one:

    func testThree() {
        let truePerformingOperationExpect = expectation(description: "truePerformingOperationExpect")
        let falsePerformingOperationExpect = expectation(description: "falsePerformingOperationExpect")
        
        sut.performingOperation = { fetching in
            if fetching {
                truePerformingOperationExpect.fulfill()
            } else {
                falsePerformingOperationExpect.fulfill()
            }
        }
        
        sut.fetch()

        wait(for: [truePerformingOperationExpect, falsePerformingOperationExpect], timeout: 0.1, enforceOrder: true)
    }

For me, this could be easily solved if I can get the current fulfilment count of an expectation, it would clean up the test a lot and I would have both of best worlds. Is it possible? Is there any other way of doing this?

Aucun commentaire:

Enregistrer un commentaire