2

For example, I don't want want to run test of the functions that select from my local data, until the test that populates the local data with the icloud data in has succeeded.

I think a proper unit test should write some predefined local itself, data before testing the local data selection methods (do people agree?). However, the calls to iCloud are asynchronous and could therefore return midway through this other test, so it would still need to be delayed until they have completed.

Cœur
  • 37,241
  • 25
  • 195
  • 267
mazz0
  • 683
  • 2
  • 8
  • 19
  • I'm assuming that xcode doesn't wait for a test's asynchronous calls (such as performing a cloudkit query) to complete before running the next test. Would I be wrong in that assumption? If so, the main part of my question is invalid as a test will never run at the same time as another, although I'd still like to know the second part - can a test be made dependant on another test succeeding fist (though you could just include the code of the other test inside your second test)? – mazz0 Nov 23 '16 at 11:34

1 Answers1

3

Unit tests are supposed to be atomic and independent, so generally this approach is not recommended. XCTest does not support this by default either. There is a discussion in this Stackoverflow post about overriding +testInvocations in Objective-C to return NSInvocation objects in the order that you'd like.

There are a couple options to consider here. One is to perform the initial test configuration in setUp. Global setup that will be performed once before all test cases run can go into a class level setUp method. If you would like to perform the setup before each test is run, then you create an instance level setUp method. (There are also matching tearDown methods that execute after the tests have run). The XCTest documentation has more details here. Note that you'll need to use the semaphore pattern described in this Stackoverflow post to ensure that any async calls complete before running the tests.

I think the most straightforward way to handle this is to include the iCloud calls in the same unit test using the expectationWithDescription class. In short, you will perform these four steps:

  1. Instantiate a new expectation, which signals when the async logic has been completed.
  2. Perform your asynchronous operation (i.e. populating data from iCloud). In this operation's callback, you can include more logic as well as assertions.
  3. At the end of the callback's method (generally), you can fulfill() the expectation. That will signal that the expectation has been met.
  4. After your async block, call the waitForExpectationsWithTimeout() method. You will invoke this method with a timeout period; if the expectation has not been fulfilled in this period, you can fail the test, log output, etc.

An example of expectation code is also provided in the Stackoverflow post that covers async calls.

Community
  • 1
  • 1
  • Yeah, I thought that was probably the way it was intended to work. And so long as I wait for the async calls to complete within each test, they'll never run at the same time as each other because XCode runs the test sequentially, right? – mazz0 Nov 29 '16 at 14:20