swiftasync-awaitclass-methodxctestcase

Call an async method from within a class method in Swift


I have a data library that needs to get loaded before all my tests. This works, but the data gets loaded before each test:

override func setUp() async throws {
   try await super.setUp()

   let task = Task {
      try await dataLibrary.load()
   }
    
   try await task.value
}

So I would like to move it to override class func setUp() which is called only once before all the tests:

override class func setUp() {
   super.setUp()

   let task = Task {
      try await dataLibrary.load()
   }
    
   try await task.value
}

First I get this error:

'async' property access in a function that does not support concurrency

So I fixed that by adding async to the method:

override class func setUp() async throws { ... }

But now:

Method does not override any method from its superclass

Is it possible what I am trying to do?


Solution

  • Is it possible what I am trying to do?

    I would ask rather: Is there any need to do what you are trying to do?

    But first things first. Your original implementation was wrong:

    override func setUp() async throws {
       try await super.setUp()
    
       let task = Task {
          try await dataLibrary.load()
       }
        
       try await task.value
    }
    

    It is pointless and silly to make a Task inside an async method, as you are already in a Task. Just say

    override func setUp() async throws {
       try await super.setUp()
       try await dataLibrary.load()
    }
    

    Now, on to your actual question. First, I would question your assumption that there is some advantage to moving this call off to the class version of the tests. But let's go with that assumption for purposes of discussion.

    Then, as you have rightly concluded, you face the fact that the class version of setUp doesn't come with an async variant. And this is reasonable, because this method is only going to run once, before all tests, so there is no harm in its being time-consuming.

    So either dataLibrary.load() should not be async to begin with (since you are just going to wait until it has finished anyway) or else you need at least to provide a non-async version of it.

    In particular, if this dataLibrary.load() is purely a testing utility, it should not be async, as there is no need for it to be. And on the other hand, if this is an method of your app, then you should not be calling it in setUp, because you shouldn't have any app dependencies in your setUp and tearDown; you need to provide a test-only implementation that does "the same thing" (whatever that may mean).