Is it possible to stub HTTP requests in Xcode 7 automated UI tests?
As Martijn correctly pointed out, because of how UI tests work, you cannot directly interact with the app at runtime, so any HTTP mocking or manipulation of things like NSUserDefaults
in a XCUITestCase
will not affect your app.
If you really need to be able to mock HTTP or setup & teardown your apps environment for specific UI tests, you will need to set launch arguments or launch environment variables before launching the app in the setUp()
method of a XCUITestCase
and then modify your app code to read the launch arguments or environment variables and bootstrap the test environment.
Example TestCase
class MyTestCase: XCTestCase {
/**
Called before each test in this test case.
*/
override func setUp() {
super.setUp()
let app = XCUIApplication()
app.launchArguments = [ "STUB_HTTP_ENDPOINTS" ]
app.launch()
}
}
Example AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
#if DEBUG
if (NSProcessInfo.processInfo().arguments.contains("STUB_HTTP_ENDPOINTS")) {
// setup HTTP stubs for tests
}
#endif
return true
}
Note: In order to use an HTTP mocking framework like OHHTTPStubs
in this example, the stubbing code and any JSON fixtures you need to use will all need to be in your app target, not the test target.
This is a very useful thread to read on the topic: https://github.com/AliSoftware/OHHTTPStubs/issues/124
Wait for all HTTP requests to finish in XCode UI tests?
Your best bet is to wait for some UI element to appear or disappear. Think of it this way:
The framework acts like a user. It doesn't care what code is running under the hood. The only thing that matters is what is visible on the screen.
That said, here is how you can wait for a label titled "Go!" to appear in your UI Tests.
let app = XCUIApplication()
let goLabel = self.app.staticTexts["Go!"]
XCTAssertFalse(goLabel.exists)
let exists = NSPredicate(format: "exists == true")
expectationForPredicate(exists, evaluatedWithObject: goLabel, handler: nil)
app.buttons["Ready, set..."].tap()
waitForExpectationsWithTimeout(5, handler: nil)
XCTAssert(goLabel.exists)
You could also extract that into a helper method. If you use some Swift compiler magic you can even get the failure message to occur on the line that called the method.
private fund waitForElementToAppear(element: XCUIElement, file: String = #file, line: UInt = #line) {
let existsPredicate = NSPredicate(format: "exists == true")
expectationForPredicate(existsPredicate, evaluatedWithObject: element, handler: nil)
waitForExpectationsWithTimeout(5) { (error) -> Void in
if (error != nil) {
let message = "Failed to find \(element) after 5 seconds."
self.recordFailureWithDescription(message, inFile: file, atLine: line, expected: true)
}
}
}
How to mock data in UITest on Xcode 7?
I think there are a lot of ways to approach this one - the difficulty is that Apple has intentionally designed UITests to run entirely separate from the app under test. That said, there are a few hooks you can use to coordinate logic in the app with logic in your tests to feed in mock data or alter the behavior of your app in any way. The two I have found most useful are launchEnvironment
and launchArguments
.
in your test - XCUIApplication().launchArguments
corresponds to NSProcessInfo.processInfo().arguments
in your app code
likewise:XCUIApplication().launchEnvironment
-> NSProcessInfo.processInfo().environment
launchEnvironment is a straight forward dictionary whereas launch arguments is an array. In your test you can feed any values you like into either of these parameters before you launch the app:
let app = XCUIApplication()
app.launchEnvironment["-FakedFeedResponse"] = "success.json"
app.launch()
Then in your application logic you can switch on these values however you like. Something like:
func fetchFeed() -> JSON {
if let fakedJSONFilename = NSProcessInfo.processInfo().environment["-FakedFeedResponse"] {
let fakePayload = fakeDataFileNamed(fakedJSONFilename)
return fakePayload
} else {
//Make network call and return a real JSON payload
}
}
Using this pattern your faked/mock data will need to be files included as members of the app target.
Is it possible to stub HTTP requests in Xcode 7 automated UI tests?
As Martijn correctly pointed out, because of how UI tests work, you cannot directly interact with the app at runtime, so any HTTP mocking or manipulation of things like NSUserDefaults
in a XCUITestCase
will not affect your app.
If you really need to be able to mock HTTP or setup & teardown your apps environment for specific UI tests, you will need to set launch arguments or launch environment variables before launching the app in the setUp()
method of a XCUITestCase
and then modify your app code to read the launch arguments or environment variables and bootstrap the test environment.
Example TestCase
class MyTestCase: XCTestCase {
/**
Called before each test in this test case.
*/
override func setUp() {
super.setUp()
let app = XCUIApplication()
app.launchArguments = [ "STUB_HTTP_ENDPOINTS" ]
app.launch()
}
}
Example AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
#if DEBUG
if (NSProcessInfo.processInfo().arguments.contains("STUB_HTTP_ENDPOINTS")) {
// setup HTTP stubs for tests
}
#endif
return true
}
Note: In order to use an HTTP mocking framework like OHHTTPStubs
in this example, the stubbing code and any JSON fixtures you need to use will all need to be in your app target, not the test target.
This is a very useful thread to read on the topic: https://github.com/AliSoftware/OHHTTPStubs/issues/124
Related Topics
How to Chain Filters in Metal for iOS
Map Object into 2D Array Swift for Tableview Sections
Wkwebview Allowslinkpreview to False Breaks Text Selection
iOS UIlabel Autoshrink So Word Doesn't Truncate to Two Lines
Using Shader Modifiers to Animate Texture in Scenekit Leads to Jittery Textures Over Time
How to Bind Multiple Observers to One Controlproperty
Spritekit Swift Node Count Issues
Multiple Lines in UItabbaritem Label
How to Add Frameworks into the Swift Project
iOS 14 Pickerview Cutting Off Text
Go Back to View Controller from Skscene
Swiftui: Navigate to Home Screen After Login Completed. Navigating Views by Button Click
Gcm Support for iOS Application When Application in Background or Killed
How to Animate a Nslayoutconstraint in Swift
How to Handle a File Sent with 'Open In...' from Another App to My Own iOS App