Xcode 7 UI 测试的页面对象模式
Page Object Pattern for Xcode 7 UI Tests
有没有人在他们的 UI 测试中成功实施了页面对象模式?我试了一下,运行 遇到了问题。当我使用谓词等待元素存在时,我在日志中收到警告。这是来自页面对象 class:
的代码片段
XCUIElement *myCoolButton = self.app.buttons[@"Super Cool Button"];
[self expectationForPredicate:self.existsPredicate evaluatedWithObject:myCoolButton handler:nil];
[self waitForExpectationsWithTimeout:5.0f handler:nil];
执行此代码时,我在日志中看到以下内容:
Questionable API usage: creating XCTestExpectation for test case -[MyPageObject (null)] which is not the currently running test case -[MyTestCase test]
当超过超时时,我在日志中看到了错误,但测试本身并没有失败。我假设这是因为谓词是在页面对象 class 中设置的,而不是测试本身。有没有人能够解决这个问题?
根据问题,我假设 waitForExpection 是写在页面对象中的 class。
通常页面对象不是从 XCTestCase 继承的,因为它们仅用于保存可能在 page.Hence 中的所有 UI 元素的引用,它们不能有断言操作(在这种情况下为 waitForExpectation)
如果您正在尝试编写一个可重复使用的函数,该函数可以在 PageObject class 中具有类似 waitForExpectation 的断言,那么您需要将测试用例作为参数传递给该函数(您的函数应该接受一个测试用例)
对于这种情况,我建议您在 XCTestCase 上编写一个类别(swift 中的扩展名),并将 XCUIElement 作为输入参数,等待 ForTheElementToExist 而不是在页面对象中写入 class.You可以避免在所有页面对象中复制相同的代码。
这里是示例代码
class LoginPageObect {
let userNameTextField = XCUIApplication().textFields["UserName"]
let passwordTextField = XCUIApplication().textFields["Password"]
func loginUser(testcase: XCTestCase) {
testcase.waitForElementToAppear(userNameTextField)
testcase.waitForElementToAppear(passwordTextField)
//Do rest of things here
}
}
extension XCTestCase {
func waitForElementToAppear(element: XCUIElement) {
let existsPredicate = NSPredicate(format: "exists == true")
expectationForPredicate(existsPredicate,
evaluatedWithObject: element, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
}
}
我用了同样的思路,通过参数传递testCase,但是后来变得很丑。 PageObjects 的一种方法(我更喜欢的一种)说你不应该在页面上有断言。
所以我想到了这个实现:
class Page {
required init(_ c: ((Bool) -> Void)? = nil) {
c?(waitForExistence())
}
func waitForExistence() -> Bool {
fatalError("Subclass of Page should override \(#function)")
}
}
然后,您可以为 XCUIElement 使用新的 XCode9 API,而不是使用需要 XCTestCase 的 waitForExpectation
: waitForExistence(timeout:)
(或 XCTWaiter
如果您需要更复杂的 期望值 )
class LoginPage: Page {
override func waitForExistence() -> Bool {
return XCUIApplication().otherElements["view_login"].waitForExistence(timeout: 10)
}
用途是:
LoginPage {
XCTAssertTrue([=12=], "Login page not shown")
}
.type(email: "solid@snake.com")
有没有人在他们的 UI 测试中成功实施了页面对象模式?我试了一下,运行 遇到了问题。当我使用谓词等待元素存在时,我在日志中收到警告。这是来自页面对象 class:
的代码片段XCUIElement *myCoolButton = self.app.buttons[@"Super Cool Button"];
[self expectationForPredicate:self.existsPredicate evaluatedWithObject:myCoolButton handler:nil];
[self waitForExpectationsWithTimeout:5.0f handler:nil];
执行此代码时,我在日志中看到以下内容:
Questionable API usage: creating XCTestExpectation for test case -[MyPageObject (null)] which is not the currently running test case -[MyTestCase test]
当超过超时时,我在日志中看到了错误,但测试本身并没有失败。我假设这是因为谓词是在页面对象 class 中设置的,而不是测试本身。有没有人能够解决这个问题?
根据问题,我假设 waitForExpection 是写在页面对象中的 class。
通常页面对象不是从 XCTestCase 继承的,因为它们仅用于保存可能在 page.Hence 中的所有 UI 元素的引用,它们不能有断言操作(在这种情况下为 waitForExpectation)
如果您正在尝试编写一个可重复使用的函数,该函数可以在 PageObject class 中具有类似 waitForExpectation 的断言,那么您需要将测试用例作为参数传递给该函数(您的函数应该接受一个测试用例)
对于这种情况,我建议您在 XCTestCase 上编写一个类别(swift 中的扩展名),并将 XCUIElement 作为输入参数,等待 ForTheElementToExist 而不是在页面对象中写入 class.You可以避免在所有页面对象中复制相同的代码。
这里是示例代码
class LoginPageObect {
let userNameTextField = XCUIApplication().textFields["UserName"]
let passwordTextField = XCUIApplication().textFields["Password"]
func loginUser(testcase: XCTestCase) {
testcase.waitForElementToAppear(userNameTextField)
testcase.waitForElementToAppear(passwordTextField)
//Do rest of things here
}
}
extension XCTestCase {
func waitForElementToAppear(element: XCUIElement) {
let existsPredicate = NSPredicate(format: "exists == true")
expectationForPredicate(existsPredicate,
evaluatedWithObject: element, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
}
}
我用了同样的思路,通过参数传递testCase,但是后来变得很丑。 PageObjects 的一种方法(我更喜欢的一种)说你不应该在页面上有断言。
所以我想到了这个实现:
class Page {
required init(_ c: ((Bool) -> Void)? = nil) {
c?(waitForExistence())
}
func waitForExistence() -> Bool {
fatalError("Subclass of Page should override \(#function)")
}
}
然后,您可以为 XCUIElement 使用新的 XCode9 API,而不是使用需要 XCTestCase 的 waitForExpectation
: waitForExistence(timeout:)
(或 XCTWaiter
如果您需要更复杂的 期望值 )
class LoginPage: Page {
override func waitForExistence() -> Bool {
return XCUIApplication().otherElements["view_login"].waitForExistence(timeout: 10)
}
用途是:
LoginPage {
XCTAssertTrue([=12=], "Login page not shown")
}
.type(email: "solid@snake.com")