-2

Is there a way to force Alamofire to do all of its work on the main thread? This is for a test scenario where I need the main thread to not continue execution until the network calls have completed and I know the status. The tests in question used to run under the XCTest framework and so I would use XCTestExpectation to wait for completion. The environment I'm using doesn't work with XCTest and so I need Alamofire to be synchronous.


Since the first 2 comments have both suggested how I should test, let me provide a little more context.

I have about 100 tests that have been running just fine for the last 2 years. The tests are NOT unit tests but UI Tests using Google's EarlGrey 1. EarlGrey 1 provides UI testing that runs under XCTest so you can combine UI Testing with white box inspection of the app state. It's great.

Earl Grey 1 does not support iOS 13 and so I am porting the tests to EarlGrey 2, which runs on top of XCUITest. For the white box aspect, you make remote calls from the test process to a bundle that is injected into your app.

In this case the "mock" is the server, but it does make network calls and these happen when I call into the test bundle. I need to know when they finish so I can return after they're done.

markand
  • 2,829
  • 1
  • 16
  • 16
  • 2
    I'd question the whole premise of the question. There is no need to test Alamofire; you know what it does. And there is almost never any reason to involve the internet in a test (except perhaps to make sure once in a while that the API/server is still there). You should mock the internet interaction and supply known data to test _your_ code. – matt Mar 24 '20 at 15:07
  • Also note that wishing Alamofire responded on the main thread and wishing that Alamofire were synchronous are two completely different things. – matt Mar 24 '20 at 15:36

1 Answers1

1

To answer your question: there's no proper way to enforce Alamofire to do calls on the main thread using Alamorefire itself. Generally speaking, you can make a thread wait for a result using a Semaphore. Alamofire seems to respond on the main thread, so that would likely result in a deadlock.

You could make the thread sleep until the callback has been handled:

var result: Data?
var done = false

// Do a call which will finish asynchonously
someCall(withBlock: { someResult in
    // Once done,
    result = someResult
    done = true
})

// Make the main thread wait
while(!done) {
    Thread.sleep(forTimeInterval: 0.1)
}

// This will be called after the block has been completed
print("\(result)")

The same can be applied to Alamofire calls, do note this can create deadlocks with threads waiting on each other.

But to help you with your problem. Ideally you do not wait to perform network calls in tests for a number of reasons, including:

  • Tests should only cover a single piece of functionality, network calls go beyond that.
  • Including network calls means external factors such as no internet connection will influence the test outcome, although it says little about your code performing as expected.

A common approach is to 'mock out' parts that should be considered out-of-scope for the test. Here's a post about doing this for Alamofire.

Kevin R
  • 8,230
  • 4
  • 41
  • 46
  • @matt - what you said was to not answer my question at all, but to simply tell me why my question was invalid and how I should be doing it differently. That was why I took a nip. :-) – markand Mar 24 '20 at 15:42
  • Kevin, thank you. I actually tried exactly the code you provided. The problem is that it seems that Alamofire does it's "work" on the background thread but executes the block on the main thread. As a result, the main thread is blocked on the wait call. Btw, I've added some more detail as to what I 'm doing. These are not unit tests and so I can't really test a single piece of functionality as I would in a unit test. – markand Mar 24 '20 at 15:45
  • @markand Hmm I think Alamofire's default response is given on the main thread. Updated the answer with a different approach, although it does seem quite hacky :) – Kevin R Mar 24 '20 at 16:03
  • @KevinR - it IS hacky, but it just might be the thing! And the response IS given on the main thread. If there were a way to change that, that could also do it in that I could signal the semaphore from a background thread. I'll give that a try. Thank you! – markand Mar 24 '20 at 16:21