How to Reset the Application Data After Each Test with Xcode 7 UI Testing

How do I reset the application data after each test with Xcode 7 UI Testing?

Not in a straight forward manner. But there are some workarounds.

The XCUIApplication can set command line arguments and environment variables that can alter your application’s behavior.

A simple example of your main.m file:

int main(int argc, char * argv[]) {
#if DEBUG
// Reset all data for UI Testing
@autoreleasepool {
for (int i = 1; i < argc; ++i) {
if (0 == strcmp("--reset-container", argv[i])) {
NSArray *folders = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSFileManager *fm = [[NSFileManager alloc] init];
for (NSString *path in folders) {
[fm removeItemAtPath:path error:nil];
}
// Also remove documents folder if necessary...
}
}
}
#endif
@autoreleasepool {
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
}
}

And in -[XCTestCase setUp] add:

XCUIApplication *app = [[XCUIApplication alloc] init];
app.launchArguments = @[@"--reset-container"];
[app launch];

Resetting app in XCUITest setup with Cucumberish

Yes, there is a way to achieve this, I use it in my tests also.

You should talk to your app using launchArguments (or eventually launchEnvironment). First, in your setUp() method, tell your app that it is in the UI-TESTING mode:

override func setUp() {
super.setUp()
continueAfterFailure = true
app.launchArguments += ["UI-TESTING"]
}

Then, in every test where you expect logged out user, inform your app that it should logout before calling XCUIApplication.launch() method:

let app = XCUIApplication()

func testWithLoggedOutUser() {
app.launchArguments += ["logout"]
app.launch()
// Continue with the test
}

Then, in your AppDelegate.swift file, read the arguments and act accordingly:

class AppDelegate: UIResponder, UIApplicationDelegate {
static var isUiTestingEnabled: Bool {
get {
return ProcessInfo.processInfo.arguments.contains("UI-TESTING")
}
}
var shouldLogout: Bool {
get {
return ProcessInfo.processInfo.arguments.contains("logout")
}
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if AppDelegate.isUiTestingEnabled {
if shouldLogout {
// Call synchronous logout method from your app
// or delete user data here
}
}
}
}

I wrote a blog post about setting local state in the app, you can check it out here.

How to delete/reset an app from iOS 13 with XCTest?

Try to press the app icon a little longer than in previous iOS versions.

    let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

func deleteMyApp() {
XCUIApplication().terminate()

let icon = springboard.icons["YourAppName"]
if icon.exists {
let iconFrame = icon.frame
let springboardFrame = springboard.frame
icon.press(forDuration: 5)

// Tap the little "X" button at approximately where it is. The X is not exposed directly
springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3) / springboardFrame.maxX, dy: (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

springboard.alerts.buttons["Delete"].tap()
}
}

Get result of each test case executed in Xcode UI tests

You are on the right track and can achieve what you're wanting to do via the XCTestObservation protocol (https://developer.apple.com/documentation/xctest/xctestobservation). You can add an observer to your test case class and I'd recommend doing this in the setUp() method since it gets executed before each test method.

override func setUp() {
super.setUp()

continueAfterFailure = false

XCUIApplication().launch()

XCTestObservationCenter.shared.addTestObserver(UITestObserver())
}

To do this you should implement a class that conforms to the XCTestObservation protocol and then provide your own implementation to the methods of interest to perform whatever actions you need/want. In your case you're probably going to want to provide an implementation for this method...

optional public func testCase(_ testCase: XCTestCase, didFailWithDescription description: String, inFile filePath: String?, atLine lineNumber: Int)

Here's a quick example of what this test observer class might look like...

import XCTest

public class UITestObserver: NSObject, XCTestObservation {
public func testCase(_ testCase: XCTestCase,
didFailWithDescription description: String,
inFile filePath: String?,
atLine lineNumber: Int) {
print("failure description: \(description)")
print("failed test case: \(testCase)")
if let filePath = filePath {
print("failure at file path: \(filePath)")
}
print("failure at line: \(lineNumber)")
}
}

This function I provided an example of above gets called whenever one of your test cases fails, so you don't need to "do" anything from within your test case class or methods.

Hope this helps!



Related Topics



Leave a reply



Submit