Download - Page Object in XCUITest
![Page 1: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/1.jpg)
![Page 2: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/2.jpg)
About Us• Nadia Lin
• Software Engineer in Test in the KKBOX Inc
• Computer vision (openCV)
• Mark Chang
• Software Engineer in Test in the KKBOX Inc
• 🐴 的學習筆記 Blog
• Github markchangjz
![Page 3: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/3.jpg)
Overview• Introduce Page Object Pattern
• Implement Page Classes (Swift 2.3)
• Strategies and Tricks
• Encountered Problems
• Q & A
![Page 5: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/5.jpg)
Cases in manual test
![Page 6: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/6.jpg)
Cases in manual test• Case1:
• Home → Chat with people → Say “Hello”
• Case2:
• Home → Swipe to delete message
Facebook Messenger
![Page 7: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/7.jpg)
Cases in automation test
![Page 8: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/8.jpg)
Cases in automation test
class UITests: XCTestCase { let app = XCUIApplication() func testChatWithPeople() { app.buttons["Home"].tap() app.cells["Nadia"].tap() app.textFields["Your message"].typeText("Hello") XCTAssertTrue(……) } }
Case 1:
Home → Chat with people → Say “Hello”
![Page 9: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/9.jpg)
Cases in automation test
class UITests: XCTestCase { let app = XCUIApplication() func testDeleteMessage() { app.buttons["Home"].tap() app.cells["Nadia"].swipeLeft() app.buttons["Delete"].tap() XCTAssertTrue(……) } }
Case 2:
Home → Swipe to delete message
![Page 10: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/10.jpg)
New SPEC Coming
![Page 11: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/11.jpg)
Modify your cases
class UITests: XCTestCase { let app = XCUIApplication() func testChatWithPeople() { app.buttons[“My Messages"].tap() app.cells["Nadia"].tap() app.textFields["Your message"].typeText("Hello") XCTAssertTrue(……) } }
Case 1:
My Messages → Chat with people → Say “Hello”
![Page 12: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/12.jpg)
Modify your cases
class UITests: XCTestCase { let app = XCUIApplication() func testChatWithPeople() { app.buttons[“My Messages"].tap() app.cells["Nadia"].tap() app.textFields["Your message"].typeText("Hello") XCTAssertTrue(……) } }
Case 2:
My Messages → Swipe to delete message
![Page 13: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/13.jpg)
class UITests: XCTestCase { let app = XCUIApplication() func testChatWithPeople() { app.buttons["My Messages"].tap() app.cells["Nadia"].tap() app.textFields["Your message"].typeText("Hello") XCTAssertTrue(……) } func testDeleteMessage() { app.buttons["My Messages"].tap() app.cells["Nadia"].swipeLeft() app.buttons["Delete"].tap() XCTAssertTrue(……) } }
Something wrong?
Hard to maintain
![Page 14: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/14.jpg)
class UITests: XCTestCase { let app = XCUIApplication() func testChatWithPeople() { app.buttons["My Messages"].tap() app.cells["Nadia"].tap() app.textFields["Your message"].typeText("Hello") XCTAssertTrue(……) } func testDeleteMessage() { app.buttons["My Messages"].tap() app.cells["Nadia"].swipeLeft() app.buttons["Delete"].tap() XCTAssertTrue(……) } }
Hard to read
Something wrong?
![Page 15: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/15.jpg)
class UITests: XCTestCase { let app = XCUIApplication() func testChatWithPeople() { app.buttons["My Messages"].tap() app.cells["Nadia"].tap() app.textFields["Your message"].typeText("Hello") XCTAssertTrue(……) } func testDeleteMessage() { app.buttons["My Messages"].tap() app.cells["Nadia"].swipeLeft() app.buttons["Delete"].tap() XCTAssertTrue(……) } }
Duplicate code
Something wrong?
![Page 17: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/17.jpg)
The advantage of Page Object
Easy to maintainEasy to read code
Reduce Duplicate code
![Page 18: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/18.jpg)
Page
![Page 19: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/19.jpg)
Page
![Page 20: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/20.jpg)
Page
![Page 21: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/21.jpg)
Page
![Page 22: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/22.jpg)
Page
![Page 23: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/23.jpg)
Tab BarHome PageCalls PageGroup PagePeople PageMe Page
![Page 24: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/24.jpg)
![Page 25: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/25.jpg)
How to know if is on this page or element ready?
Wait
![Page 26: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/26.jpg)
Wait
![Page 27: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/27.jpg)
Wait for page loadedimport XCTest
class Page { static let app = XCUIApplication() private func waitForPageLoaded() { } required init() { waitForPageLoaded() } }
![Page 28: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/28.jpg)
Predicateclass HomePage: Page { override func waitForPageLoaded() { let homeButton = app.buttons["Home"] let exists = NSPredicate(format: "exists == true") expectation(for: exists, evaluatedWithObject: homeButton, handler: nil) waitForExpectations(timeout: 5, handler: nil) } }
Reference
![Page 29: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/29.jpg)
func testChatWithPeople() { let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello") XCTAssertEqual(chatRoomPage.leatestMessage, "Hello") }
Reduce duplicate code
app.cells[“Nadia”].tap()
![Page 30: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/30.jpg)
func testChatWithPeople() { let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello") XCTAssertEqual(chatRoomPage.leatestMessage, "Hello") }
Reduce duplicate code func chat(with name: String) -> ChatRoomPage { app.cells[name].tap() return ChatRoomPage() }
![Page 31: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/31.jpg)
func testChatWithPeople() { let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello") XCTAssertEqual(chatRoomPage.leatestMessage, "Hello") }
Reduce duplicate code
app.textFields["Your message"].typeText("Hello")
![Page 32: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/32.jpg)
func testChatWithPeople() { let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello") XCTAssertEqual(chatRoomPage.leatestMessage, "Hello") }
Reduce duplicate code
func sendMessage(msg: String) -> ChatRoomPage { app.textFields["Your message"].typeText(msg) return ChatRoomPage() }
![Page 33: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/33.jpg)
HomePage
- newMessageButton: XCUIElement
- userCell(index: Int): XCUIElement - waitForPageLoaded(): Void + getRecentMessage(index: Int): String + chat(with name: String): ChatPage + goToNewMessagePage(): NewMessagePage + goToSearchPage(): SearchPage + goToHomePage(): HomePage + goToCallsPage(): CallsPage + goToGroupsPage(): GroupsPage + goToPeoplePage(): PeoplePage + goToMePage(): MePage
![Page 34: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/34.jpg)
Page Object Pattern
Chat Room Page
send message
Home Page
chat
back
People Page
chatgo to people page
Search Page
go to search page
search
go to search page
![Page 35: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/35.jpg)
Strategies & Tricks
• Protocol Extensions • Tab Bar
• Search Bar
• Generics • Go Back
• Go To Different Page
![Page 36: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/36.jpg)
Tab Bar
![Page 37: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/37.jpg)
Tab Bar
protocol MessengerTabBar { func goToHomePage() -> HomePage func goToCallsPage() -> CallsPage func goToGroupsPage() -> GroupsPage func goToPeoplePage() -> PeoplePage func goToMePage() -> MePage }
![Page 38: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/38.jpg)
Tab Barprotocol MessengerTabBar { // ... }
extension MessengerTabBar { private var homeButton: XCUIElement { return Page.app.buttons["Home"] } // ... func goToHomePage() -> HomePage { homeButton.tap() return HomePage() } // ... }
![Page 39: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/39.jpg)
Tab Barfinal class HomePage: Page, MessengerTabBar { // ... } HomePage
![Page 40: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/40.jpg)
let homePage = HomePage()
homePage.gotoGroupsPage() .gotoMePage()
![Page 41: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/41.jpg)
let homePage = HomePage()
homePage.goToGroupsPage() .gotoMePage()
![Page 42: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/42.jpg)
let homePage = HomePage()
homePage.goToGroupsPage() .goToMePage()
![Page 43: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/43.jpg)
Protocol Extensions• There are have MessengerSearchBar
![Page 44: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/44.jpg)
Protocol Extensions
Chat Room Page
send message
Home Page
chat
back
People Page
chatgo to people page
Search Page
go to search page
search
go to search page
![Page 45: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/45.jpg)
Protocol Extensionsfinal class HomePage: Page, MessengerTabBar, MessengerSearchBar { // ... }
final class GroupsPage: Page, MessengerTabBar, MessengerSearchBar { // ... }
final class MePage: Page, MessengerTabBar, MessengerSearchBar { // ... }
final class PeoplePage: Page, MessengerTabBar, MessengerSearchBar { // ... }
![Page 46: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/46.jpg)
Back
![Page 47: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/47.jpg)
HomePage
backToHomePage()
backToPeoplePage()
PeoplePage ChatRoomPage
Back
![Page 48: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/48.jpg)
Back
Chat Room Page
send message
Home Page
chat
back
People Page
chatgo to people page
Search Page
go to search page
search
go to search page
![Page 49: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/49.jpg)
final class ChatRoomPage: Page {
private let backButton = Page.app.buttons[“Back”] // ... func backToHomePage() -> HomePage { backButton.tap() return HomePage() } func backToPeoplePage() -> PeoplePage { backButton.tap() return PeoplePage() } // ... }
Back
![Page 50: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/50.jpg)
final class ChatRoomPage: Page {
private let backButton = Page.app.buttons[“Back”] // ... func backTo<T: Page>(type: T.Type) -> T { backButton.tap() return type.init() }
// ... }
Back
Generics
![Page 51: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/51.jpg)
HomePage ChatRoomPage
1. chat(with:" ")
2. backTo(HomePage)
homePage.chat(with:" ").backTo(HomePage)
![Page 52: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/52.jpg)
Taps the same button,
but it could go to different page
Generics
Can we return two page classes !?
![Page 53: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/53.jpg)
GenericsTap play button Possible 1
Go to Nowplaying pagePossible 2
Go to Chart page
![Page 54: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/54.jpg)
Genericsfunc playPlaylistAndExpectTransitionToPage<T: Page>(type: T.Type) -> T { //… playButton.tap()
return type.init() }
Possible 1. Go to Nowplaying page chartPage.playPlaylistAndExpectTransitionToPage(NowplayingPage)
Possible 2. Go to Chart page chartPage.playPlaylistAndExpectTransitionToPage(ChartPage)
![Page 55: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/55.jpg)
Encountered Problems
![Page 56: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/56.jpg)
Sets Element Accessibility• Accessibility data makes UI testing possible
Reference: UI Testing in Xcode - WWDC 2015 - Videos - Apple Developer
Test
abili
ty
Quality of Accessibility Data
![Page 57: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/57.jpg)
Speed Up Testing• Set launch arguments to speed up testing
Tutorial View
![Page 58: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/58.jpg)
Speed Up Testingoverride func setUp() { //… let app = XCUIApplication() app.launchArguments.append("-forceDoNotShowTutorial") app.launchArguments.append("1") app.launch() //… }
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults]; if ([standardDefaults boolForKey:@"forceDoNotShowTutorial"]) { [UserConfig sharedInstance].everShowTutorial = YES; }
• In Test Code (Swift 2.3) - Set launch arguments
• In App Code (Objective-C) - Read launch arguments
![Page 59: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/59.jpg)
Reduce Motion• UI animation might cause test fail while transit
![Page 60: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/60.jpg)
Reduce Motion• Settings > General > Accessibility > Reduce Motion
• UIAccessibilityIsReduceMotionEnabled()
• Returns a Boolean value indicating whether reduce motion is enabled (API Reference)
• true if the user has enabled Reduce Motion in Settings; otherwise, false
![Page 61: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/61.jpg)
Turn Off Auto-Correction• Input string might be changed
• Settings > General > Keyboards
![Page 62: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/62.jpg)
Slow Network Speed• Using Network Link Conditioner tool to restrict
network speed. (For simulator)
![Page 63: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/63.jpg)
Software Update• Don’t remind me to upgrade iOS ( Tutorial Link )
![Page 64: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/64.jpg)
Recap• Make your page object at the user level,
rather than expose implement details
• Protocol Extensions: Extract common actions
• Generics: Go to indicated page
• iOS-Messenger-Page-Object
![Page 65: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/65.jpg)
![Page 66: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/66.jpg)
Q & A• Q: ⼤概你們就是把⼀個,⽤ state machine 的概念,配合 IoC 反轉注⼊的概念,把這個精神套⼊到你的 UI test 這個精神、這個動作上⾯。那我想要問的就是,你們費了這麼多功夫,實現了這個 page object,你覺得它有什麼缺點,會不會變成說你做了⼀個這麼精緻的 page object 的 test,會不會變成我還要再寫⼀個測試程式去測這個測試程式?
• A: (Mark) Page object ⽬前我們實作起來,看起來是 ... 缺點來說 我到⽬前都覺得滿順利的,因為我們⼀開始在實作的時候,其實都是⽤ 直接點元件 這樣點 這樣點 然後就其實也看不出來測試到底在測試什麼東西,然後你再包裝成 page object 的話,就可讀性都⽐較⾼,⾄於說包裝起來是不是要測試,我們⽬前是沒有這⼀層的測試,不然這樣其實也測不完,所以我們這部份是沒有再繼續對 page object 這個 pattern 去做測試。
![Page 67: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/67.jpg)
Q & A• Q: 那你怎麼 guarantee 說你的 page object 是沒有問題的。
• A: (Nadia) 我覺得這個問題感覺像是說,你怎麼確定你寫的測試是正確的? (對) 但是,既然我們寫了⾃動化測試,我們就要對它有⼀定的⾃信 (ok),不然永遠都⼿動測試就好了,我們適時要相信⼀下機器,我們是這麼想的。
• Q: (Nick) 我想請問⼀下,現在就是從五⽉開始到現在,花了半年多的時間,所以現在寫的測試是真的有投⼊到現⾏的 project 上嗎?
• A: (Nadia) 我們現在是積極地在擴充我們的 code coverage,應該差不多可以放上去,只是我們有某些 feature 的地⽅還沒有實作到⾃動化測試,所以還不敢讓它當做真正的測試結果。
• Q: (Nick) 第⼆個問題是,我知道 KKBOX 有 support iOS 跟 Android 的 app,你們之前可能想要做⼀個⾃動化測試的 ... 應該說通吃兩個平台,那你們現在是之後打算會拆開嗎?
• A: (Nadia) 對,我們現在要拆開。
• Q: (Nick) 對,這點可能就是滿好奇的,因為我想說現在滿多⼈ 有些公司 ⽐如說測試⼈員沒有那麼多,他們會去找能夠跨平台的⼯具,像 Appium 或 Calabash 這種東西,那我覺得拆開這件事情,其實我之前也有想過,因為我覺得拆開有它的好處,我想說滿想聽聽看不知道可不可以分享,為什麼最後決定要拆開? (Zonble: Jeremy 要不要上⼀下? 做決定的⼈在這裡...)
![Page 68: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/68.jpg)
Q & A• A: (Jeremy) 或許⼤家都知道 KKBOX 之前在公開的場合有 share 我們在使⽤ Appium + Robot
Framework 之類的 tool,要在同⼀個 case 裡⾯通知所有的平台,那當然⾮常理想,不過相信各位有⽤過 Appium 的,會發覺其實它三不五⼗會壞掉,就是沒那麼穩定,那其實各位如果有⼀直在追 testing tool 的話,你會發覺這⼀年多來,其實官⽅的動作越來越⼤,為什麼在這之前所有 3rd party 的 tool ⽐如說剛提到的 Calabash、Robotium ⼀⼤堆,你會發覺好多的 project,好多都已經 deprecated、不再 maintain 了,其實我們也漸漸看到這個趨勢,其實以最近的 case 來講,XCUITest 在去年就已經推出了,可是 Appium 到今年好像... 不知道幾個⽉前才整完,所以在這之前你都要忍受被 Apple 放棄的 UIAutomation 時不時這裡壞、那裡壞的問題,我們是看到這個趨勢,那我們會覺得說,應該要重新思考⼀下,因為畢竟時空環境已經不⼀樣了,再來就是我們希望 QA 的開發⼯作能夠跟 RD 的開發⼯作能夠結合得更緊密⼀點,⽐如說以前我們⽤ Appium 或許 RD 還要花時間去學,你⽤ Python 寫、你⽤ Ruby 寫,就是跟他們的 tool 是不⼀樣的,那其實在 GTAC 有幾個場次也提到 automation 實作的⽅式,其實最好是跟著 RD 的語⾔下去做,所以當他今天要進來協助你的時候,他是可以直接協助的,最主要有這幾點考量。就是官⽅的動作已經不是 3rd party 可以追得上的,然後再來就是跟 RD 的 cowork,那透過這樣的⽅式你會得到更多 official 的 support,然後像 Appium 以前很難算 code coverage,我們 adopt XCUITest 之後,testing tool 就可以直接算,那或許我們在做 E2E testing 算 coverage 沒有那麼直接的效益,可是我們⾄少知道說哪個⾯向,因為我們看得出來說哪些 function 被 cover 得⽐較多,所以我們下⼀個在做的時候就會往另⼀個⽅向去做,讓每⼀個 function 都能夠被 cover 到。那包括我們的 Android 現在也是⽤ Espresso,也都有這⽅⾯的好處。
![Page 69: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/69.jpg)
Q & A• Q: (Hanyu) 因為我也有寫 UI testing,我⼀直很好奇⼀點就是,因為 UI testing 不能在 Jenkins 上跑,它要在 Mac server 上跑,請問你們怎麼解決這個問題?
• A: (Zonble) 我們在 Mac server 上跑。
• Q: (Hanyu) 可是這樣⼦你們就,我不知道怎麼串接、那個架構是怎麼樣,我滿好奇的,因為我知道你們好像是⼀台 Jenkins 然後掛 4、5 台 Mac server 吧。
• A: (Zonble) iOS team 的 Jenkins 跟 QA team 其實分開,有分開來的機器,然後兩個部⾨間再互相 sync。你在我們部落格看到的我那篇⽂章講我們⾃⼰的 build system,然後我們會 build ... 那台機器在 iOS team 這邊主要在 build 出 daily build,幾乎我們 RD 每個 branch 都有編出⾃⼰的,幾乎每個 revision 都編出⼀個版本,然後同時在執⾏,像我們整個 app 有 4、5 個⾯向,app 裡頭的播放器、跟 server 的溝通,那邊寫了⼀⼤堆的單元測試,在 Jenkins 上我們主要跑這些,那今年轉到 XCUITest 那 Jeremy 他們就 study 這些,看起來那個 Jenkins 跑這個東西就是跑得不順,就另外再去架了那個 Xcode Server。然後 Xcode Server 就定時去拉新的 code 然後在上⾯執⾏。
![Page 70: Page Object in XCUITest](https://reader034.vdocuments.pub/reader034/viewer/2022052514/587a21791a28abb4238b7a7d/html5/thumbnails/70.jpg)
Reference• Page Object
• DSL, Page Object and Selenium – a way to reliable functional tests
• Best Practices - SELENIUM DOCUMENTATION
• PageObjects · SeleniumHQ_selenium Wiki · GitHub
• XCUITest
• UI Testing Cheat Sheet and Examples · masilotti.com
• XCTest and the Page Object Model
• Swift
• Getting Started with Swift