问题
I have a class teardown which is trying to remove the app, but it doesn't recognize app.terminate().
class DeviceSettingsUtilities : UITestUtilities {
func removeApp(productName:String){
print("in teardown")
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
XCUIApplication().terminate() // this does nothing
XCUIApplication(bundleIdentifier: "com.xxx.xxxx").terminate()//this does nothing too, but this works when called as an instance teardown
sleep(5)
springboard.activate()
let icon = springboard.icons.matching(identifier: productName).firstMatch
// icon.exists is false when called as a class teardown
// icon.exists is true when called as an instance teardown
if icon.exists {
let iconFrame = icon.frame
let springboardFrame = springboard.frame
icon.press(forDuration:1.3)
springboard.coordinate(withNormalizedOffset: CGVector(dx: ((iconFrame.minX + 3) / springboardFrame.maxX), dy:((iconFrame.minY + 3) / springboardFrame.maxY))).tap()
sleep(5)
springboard.buttons["Delete"].firstMatch.tap()
sleep(5)
}
XCUIApplication().terminate()
}
}
This is being called in the test case class teardown method as shown below
override class func tearDown() {
super.tearDown()
let deviceSettings = DeviceSettingsUtilities()
deviceSettings.removeApp(productName: ProductName.rawValue)
}
This just doesnt delete the app, But if i change class func tearDown() to func tearDown() , it deletes the app with no problem. Not sure what i am missing. Any suggestions ?
回答1:
The app is not being reset when you put the code in the class tearDown
method because that method only runs once all the tests in the class are complete. The instance tearDown
is the best place to put code that you want to run after every test.
From Apple's documentation:
For each class, testing starts by running the class setup method. For each test method, a new instance of the class is allocated and its instance setup method executed. After that it runs the test method, and after that the instance teardown method. This sequence repeats for all the test methods in the class. After the last test method teardown in the class has been run, Xcode executes the class teardown method and moves on to the next class. This sequence repeats until all the test methods in all test classes have been run.
回答2:
I'm using the below workaround to terminate the app after last test case of a class.
class BaseClass: XCTestCase {
static var LastTestCaseName: String = ""
override class func setUp() {
LastTestCaseName = defaultTestSuite.tests.last!.name
super.setUp()
}
override func tearDown() {
let app = XCUIApplication()
if BaseClass.LastTestCaseName == testRun?.test.name {
app.terminate()
}
}
}
回答3:
This seems like a bug in latest Xcode 10.
XCUIApplication.terminate()
doesn't seem to work in tearDown()
when declared as class
.
This can be solved in two ways:
The first option is to use:
override func tearDown() {
XCUIApplication().terminate()
super.tearDown()
}
instead of:
override class func tearDown() {…}
Or, terminate the app differently (press home button, open different app...). However, I would use the first way.
Also consider reporting this to Apple, so they can fix it.
Edit: This has nothing to do with app state (XCUIApplication().state.rawValue
), since it is same in test and in tearDown()
(4 = running foreground
). Also - official documentation says that .terminate()
will terminate app, which has a debug session with Xcode, but the debug session is active in tearDown()
as well. So it is really probably a bug in Xcode.
来源:https://stackoverflow.com/questions/53181823/xcuitest-class-teardown-isnt-deleting-the-app-but-works-if-its-instance-teardow