Mizmor
Mizmor

Reputation: 1421

XCTest Single Asynchronous SetUp With Semaphores

I am working on testing an API through Alamofire. I need to make a single call to the server to prepare it for the integration test. Once that is done, I am ready to start running tests.

The usual override setUp() is run for every test, so I do not want to do that.

I have therefore chosen to override the class setUp() as described here: https://developer.apple.com/reference/xctest/xctestcase

That's all well and good, but now, I no longer can use the standard waitForExpectations. (In the class override setUp()) I get several compiler errors that tell me that I am no longer calling the same waitForExpectations because I am in a class method, not a test case.

To try to get around this, I wanted to use a semaphore like so:

class ServiceLayerTests: XCTestCase {
    static var apiService: APIService = APIService()
    let sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: ["http://localhost:3000/": .disableEvaluation]))
    static var companyManger: UserWebResource?
    static var companyManagerID = -1
    override class func setUp() {
        apiService.baseURL = "http://localhost:3000/"
        beginIntegrationTests()
    }

    class func beginIntegrationTests() {
        var semaphore = DispatchSemaphore(value: 0)
        apiService.beginIntegrationTests(completion: {resource, error in
            if let resource = resource {
                if let manager = resource as? UserWebResource {
                    companyManger = manager
                    companyManagerID = manager.id
                    semaphore.signal()

                }
            }
        })
        _ = semaphore.wait(timeout: DispatchTime.distantFuture)
  }
}

This does not work. Under the hood, there is an alamo fire call to the server and it responds with the user to use for the integration tests. I do see the server spinning, so I know that the actual communication is happening, but I never get into the completion closure.

I suspect I am not understanding how Swift does semaphores and that I have created a deadlock somehow. If somebody has a better solution, I'd be more than happy to hear it.

Upvotes: 4

Views: 972

Answers (2)

Andy
Andy

Reputation: 4531

You can create the expectation as a lazy var that executes your one-time set up and fulfills on completion.

At the beginning of your per-test setUp() function you can wait for that expectation.

None of your tests will run until it is fulfilled, and the initial setup will run only once.

class WaitForSetup_Tests: XCTestCase {

    lazy var initialSetupFinished: XCTestExpectation = {
        let initialSetupFinished = expectation(description: "initial setup finished")

        initialSetupTask() { // your setup task that executes this closure on completion
            initialSetupFinished.fulfill()
            return
        }

        return initialSetupFinished
    }()

    override func setUp() {
        wait(for: [initialSignOutFinished], timeout: 2.0)
        // do your per-test setup here
    }
}

Note: This solution avoids using the override class function setUp() class method, because I couldn't figure out how to use the expectations except for in an instance.

Upvotes: 0

Mike D
Mike D

Reputation: 4946

I get several compiler errors that tell me that I am no longer calling the same waitForExpectations because I am in a class method, not a test case

That makes sense. What you probably want is to refactor so that you are in a test case:

override class func setUp() {
    apiService.baseURL = "http://localhost:3000/"
}

func testIntegrationTests() {
    let urlExpectation = expectation(description: "INTEGRATION TEST")
    apiService.beginIntegrationTests(completion: {resource, error in
        // ...
        urlExpectation.fulfill()
    })

   // not sure what an acceptable timeout would be, I chose this at random
   waitForExpectations(timeout: 25) { error in
       if let error = error {
           print("Error: \(error.localizedDescription)")
       }
   }
}

One of the best resources with some good test examples can be found here: http://nshipster.com/xctestcase/

Upvotes: 1

Related Questions