SlideShare a Scribd company logo
1 of 70
Download to read offline
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
Overview
• Introduce Page Object Pattern

• Implement Page Classes (Swift 2.3)

• Strategies and Tricks

• Encountered Problems

• Q & A
What is Page Object?
Reference by Martin Fowler
Cases in manual test
Cases in manual test
• Case1:
• Home → Chat with people → Say “Hello”
• Case2:
• Home → Swipe to delete message
Facebook
Messenger
Cases in automation test
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”
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
New SPEC Coming
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”
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
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
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?
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?
So, What is Page Object?
Reference by Martin Fowler
The advantage of Page Object
Easy to maintain
Easy to read code
Reduce Duplicate code
Page
Page
Page
Page
Page
Tab Bar
Home Page

Calls Page

Group Page

People Page

Me Page
How to know if is on this
page or element ready?
Wait
Wait
Wait for page loaded
import XCTest
class Page {
static let app = XCUIApplication()
private func waitForPageLoaded() { }
required init() {
waitForPageLoaded()
}
}
Predicate
class 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
func testChatWithPeople() {
let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello")
XCTAssertEqual(chatRoomPage.leatestMessage, "Hello")
}
Reduce duplicate code
app.cells[“Nadia”].tap()
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()
}
func testChatWithPeople() {
let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello")
XCTAssertEqual(chatRoomPage.leatestMessage, "Hello")
}
Reduce duplicate code
app.textFields["Your message"].typeText("Hello")
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()
}
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 Object Pattern
Chat Room
Page
send message
Home
Page
chat
back
People
Page
chat
go to people page
Search
Page
go to search page
search
go to search page
Strategies & Tricks
• Protocol Extensions
• Tab Bar

• Search Bar
• Generics
• Go Back

• Go To Different Page
Tab Bar
Tab Bar
protocol MessengerTabBar {
func goToHomePage() -> HomePage
func goToCallsPage() -> CallsPage
func goToGroupsPage() -> GroupsPage
func goToPeoplePage() -> PeoplePage
func goToMePage() -> MePage
}
Tab Bar
protocol MessengerTabBar {
// ...
}
extension MessengerTabBar {
private var homeButton: XCUIElement {
return Page.app.buttons["Home"]
}
// ...
func goToHomePage() -> HomePage {
homeButton.tap()
return HomePage()
}
// ...
}
Tab Bar
final class HomePage: Page, MessengerTabBar {
// ...
}
HomePage
let homePage = HomePage()
homePage.gotoGroupsPage()
.gotoMePage()
let homePage = HomePage()
homePage.goToGroupsPage()
.gotoMePage()
let homePage = HomePage()
homePage.goToGroupsPage()
.goToMePage()
Protocol Extensions
• There are have MessengerSearchBar
Protocol Extensions
Chat Room
Page
send message
Home
Page
chat
back
People
Page
chat
go to people page
Search
Page
go to search page
search
go to search page
Protocol Extensions
final class HomePage: Page, MessengerTabBar, MessengerSearchBar {
// ...
}
final class GroupsPage: Page, MessengerTabBar, MessengerSearchBar {
// ...
}
final class MePage: Page, MessengerTabBar, MessengerSearchBar {
// ...
}
final class PeoplePage: Page, MessengerTabBar, MessengerSearchBar {
// ...
}
Back
HomePage
backToHomePage()
backToPeoplePage()
PeoplePage ChatRoomPage
Back
Back
Chat Room
Page
send message
Home
Page
chat
back
People
Page
chat
go to people page
Search
Page
go to search page
search
go to search page
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
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
HomePage ChatRoomPage
1. chat(with:" ")
2. backTo(HomePage)
homePage.chat(with:" ").backTo(HomePage)
Taps the same button, 

but it could go to different page
Generics
Can we return two page classes !?
Generics
Tap play button
Possible 1
Go to Nowplaying page
Possible 2
Go to Chart page
Generics
func 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)
Encountered Problems
Sets Element Accessibility
• Accessibility data makes UI testing possible
Reference: UI Testing in Xcode - WWDC 2015 - Videos - Apple Developer
Testability
Quality of Accessibility Data
Speed Up Testing
• Set launch arguments to speed up testing
Tutorial View
Speed Up Testing
override 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
Reduce Motion
• UI animation might cause test fail while transit
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
Turn Off Auto-Correction
• Input string might be changed

• Settings > General > Keyboards
Slow Network Speed
• Using Network Link Conditioner tool to restrict
network speed. (For simulator)
Software Update
• Don’t remind me to upgrade iOS ( Tutorial Link )
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
Q & A
• Q: ⼤概你們就是把⼀個,⽤ state machine 的概念,配合 IoC 反轉注⼊
的概念,把這個精神套⼊到你的 UI test 這個精神、這個動作上⾯。那
我想要問的就是,你們費了這麼多功夫,實現了這個 page object,你
覺得它有什麼缺點,會不會變成說你做了⼀個這麼精緻的 page object
的 test,會不會變成我還要再寫⼀個測試程式去測這個測試程式?

• A: (Mark) Page object ⽬前我們實作起來,看起來是 ... 缺點來說 我到
⽬前都覺得滿順利的,因為我們⼀開始在實作的時候,其實都是⽤ 直接
點元件 這樣點 這樣點 然後就其實也看不出來測試到底在測試什麼東
西,然後你再包裝成 page object 的話,就可讀性都⽐較⾼,⾄於說包
裝起來是不是要測試,我們⽬前是沒有這⼀層的測試,不然這樣其實也
測不完,所以我們這部份是沒有再繼續對 page object 這個 pattern 去
做測試。
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 要不要上⼀下? 做決定的⼈在這裡...)
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,也都有這⽅⾯的好處。
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 然後在上⾯執
⾏。
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

More Related Content

What's hot

Browser Automation with Playwright – for integration, RPA, UI testing and mor...
Browser Automation with Playwright – for integration, RPA, UI testing and mor...Browser Automation with Playwright – for integration, RPA, UI testing and mor...
Browser Automation with Playwright – for integration, RPA, UI testing and mor...Lucas Jellema
 
퍼블리싱 협의 체크리스트
퍼블리싱 협의 체크리스트퍼블리싱 협의 체크리스트
퍼블리싱 협의 체크리스트규연 황
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first stepsRenato Primavera
 
Page object with selenide
Page object with selenidePage object with selenide
Page object with selenideCOMAQA.BY
 
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹Johnny Sung
 
Writing and using Hamcrest Matchers
Writing and using Hamcrest MatchersWriting and using Hamcrest Matchers
Writing and using Hamcrest MatchersShai Yallin
 
使用 switch/case 重構程式碼
使用 switch/case 重構程式碼使用 switch/case 重構程式碼
使用 switch/case 重構程式碼Weizhong Yang
 
Entity System Architecture with Unity - Unite Europe 2015
Entity System Architecture with Unity - Unite Europe 2015Entity System Architecture with Unity - Unite Europe 2015
Entity System Architecture with Unity - Unite Europe 2015Simon Schmid
 
Javascript this keyword
Javascript this keywordJavascript this keyword
Javascript this keywordPham Huy Tung
 
Robot Framework Dos And Don'ts
Robot Framework Dos And Don'tsRobot Framework Dos And Don'ts
Robot Framework Dos And Don'tsPekka Klärck
 
05 junit
05 junit05 junit
05 junitmha4
 
Create an architecture for web test automation
Create an architecture for web test automationCreate an architecture for web test automation
Create an architecture for web test automationElias Nogueira
 
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...Postman
 
Jetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning TourJetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning TourMatthew Clarke
 

What's hot (20)

Browser Automation with Playwright – for integration, RPA, UI testing and mor...
Browser Automation with Playwright – for integration, RPA, UI testing and mor...Browser Automation with Playwright – for integration, RPA, UI testing and mor...
Browser Automation with Playwright – for integration, RPA, UI testing and mor...
 
퍼블리싱 협의 체크리스트
퍼블리싱 협의 체크리스트퍼블리싱 협의 체크리스트
퍼블리싱 협의 체크리스트
 
JUnit & Mockito, first steps
JUnit & Mockito, first stepsJUnit & Mockito, first steps
JUnit & Mockito, first steps
 
Page object with selenide
Page object with selenidePage object with selenide
Page object with selenide
 
A Step Towards Data Orientation
A Step Towards Data OrientationA Step Towards Data Orientation
A Step Towards Data Orientation
 
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹炎炎夏日學 Android 課程 -  Part1: Kotlin 語法介紹
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
 
Writing and using Hamcrest Matchers
Writing and using Hamcrest MatchersWriting and using Hamcrest Matchers
Writing and using Hamcrest Matchers
 
Java Unit Testing
Java Unit TestingJava Unit Testing
Java Unit Testing
 
使用 switch/case 重構程式碼
使用 switch/case 重構程式碼使用 switch/case 重構程式碼
使用 switch/case 重構程式碼
 
Entity System Architecture with Unity - Unite Europe 2015
Entity System Architecture with Unity - Unite Europe 2015Entity System Architecture with Unity - Unite Europe 2015
Entity System Architecture with Unity - Unite Europe 2015
 
Javascript this keyword
Javascript this keywordJavascript this keyword
Javascript this keyword
 
Robot Framework Dos And Don'ts
Robot Framework Dos And Don'tsRobot Framework Dos And Don'ts
Robot Framework Dos And Don'ts
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
Functional C++
Functional C++Functional C++
Functional C++
 
Robot Framework
Robot FrameworkRobot Framework
Robot Framework
 
05 junit
05 junit05 junit
05 junit
 
Create an architecture for web test automation
Create an architecture for web test automationCreate an architecture for web test automation
Create an architecture for web test automation
 
Introduction to Robot Framework
Introduction to Robot FrameworkIntroduction to Robot Framework
Introduction to Robot Framework
 
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
POST/CON 2019 Workshop: Testing, Automated Testing, and Reporting APIs with P...
 
Jetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning TourJetpack Compose - A Lightning Tour
Jetpack Compose - A Lightning Tour
 

Viewers also liked

iOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + GherkiniOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + GherkinKenneth Poon
 
Getting Started with XCTest and XCUITest for iOS App Testing
Getting Started with XCTest and XCUITest for iOS App TestingGetting Started with XCTest and XCUITest for iOS App Testing
Getting Started with XCTest and XCUITest for iOS App TestingBitbar
 
iOS UI Testing in Xcode
iOS UI Testing in XcodeiOS UI Testing in Xcode
iOS UI Testing in XcodeJz Chang
 
iOS UIAutomation
iOS UIAutomation iOS UIAutomation
iOS UIAutomation Jz Chang
 
Automated Xcode 7 UI Testing
Automated Xcode 7 UI TestingAutomated Xcode 7 UI Testing
Automated Xcode 7 UI TestingJouni Miettunen
 
Sunrise pc support heart bleed scam alert
Sunrise pc support heart bleed scam alertSunrise pc support heart bleed scam alert
Sunrise pc support heart bleed scam alertjimforner
 
Advanced Project 1: Heart Bleed
Advanced Project 1: Heart BleedAdvanced Project 1: Heart Bleed
Advanced Project 1: Heart BleedKenneth Poon
 
PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)
PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)
PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)Kenneth Poon
 
CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]
CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]
CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]Kenneth Poon
 
UI Testing with Earl Grey
UI Testing with Earl GreyUI Testing with Earl Grey
UI Testing with Earl GreyShyam Bhat
 
Appiumのテスト結果レポートをsahaginで作ってみる
Appiumのテスト結果レポートをsahaginで作ってみるAppiumのテスト結果レポートをsahaginで作ってみる
Appiumのテスト結果レポートをsahaginで作ってみるNozomi Ito
 
iOS Test-Driven Development
iOS Test-Driven DevelopmentiOS Test-Driven Development
iOS Test-Driven DevelopmentPablo Villar
 
Choosing the Best Open Source Test Automation Tool for You
Choosing the Best Open Source Test Automation Tool for YouChoosing the Best Open Source Test Automation Tool for You
Choosing the Best Open Source Test Automation Tool for YouPerfecto by Perforce
 

Viewers also liked (14)

iOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + GherkiniOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + Gherkin
 
Getting Started with XCTest and XCUITest for iOS App Testing
Getting Started with XCTest and XCUITest for iOS App TestingGetting Started with XCTest and XCUITest for iOS App Testing
Getting Started with XCTest and XCUITest for iOS App Testing
 
iOS UI Testing in Xcode
iOS UI Testing in XcodeiOS UI Testing in Xcode
iOS UI Testing in Xcode
 
iOS UIAutomation
iOS UIAutomation iOS UIAutomation
iOS UIAutomation
 
Automated Xcode 7 UI Testing
Automated Xcode 7 UI TestingAutomated Xcode 7 UI Testing
Automated Xcode 7 UI Testing
 
Sunrise pc support heart bleed scam alert
Sunrise pc support heart bleed scam alertSunrise pc support heart bleed scam alert
Sunrise pc support heart bleed scam alert
 
Advanced Project 1: Heart Bleed
Advanced Project 1: Heart BleedAdvanced Project 1: Heart Bleed
Advanced Project 1: Heart Bleed
 
PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)
PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)
PropertyGuru is Hiring. iOS / Android Engineer (Bangkok, Thailand)
 
CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]
CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]
CNY Distribution of Oranges, Uplifting the spirit [@TPCTMC]
 
UI Testing with Earl Grey
UI Testing with Earl GreyUI Testing with Earl Grey
UI Testing with Earl Grey
 
Appiumのテスト結果レポートをsahaginで作ってみる
Appiumのテスト結果レポートをsahaginで作ってみるAppiumのテスト結果レポートをsahaginで作ってみる
Appiumのテスト結果レポートをsahaginで作ってみる
 
iOS Test-Driven Development
iOS Test-Driven DevelopmentiOS Test-Driven Development
iOS Test-Driven Development
 
Choosing the Best Open Source Test Automation Tool for You
Choosing the Best Open Source Test Automation Tool for YouChoosing the Best Open Source Test Automation Tool for You
Choosing the Best Open Source Test Automation Tool for You
 
SlideShare 101
SlideShare 101SlideShare 101
SlideShare 101
 

Similar to Page Object in XCUITest

Go语言web开发
Go语言web开发Go语言web开发
Go语言web开发Andy Shi
 
Kind editor设计思路
Kind editor设计思路Kind editor设计思路
Kind editor设计思路taobao.com
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐zhangsuoyong
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计yiming he
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式Shengyou Fan
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型keelii
 
行動平台上利用Facebook API開發社群應用程式
行動平台上利用Facebook API開發社群應用程式行動平台上利用Facebook API開發社群應用程式
行動平台上利用Facebook API開發社群應用程式Mu Chun Wang
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文Guo Albert
 
Kindeditor 设计思路
Kindeditor 设计思路Kindeditor 设计思路
Kindeditor 设计思路luolonghao
 
Java Jdk6学习笔记[Ppt]
Java Jdk6学习笔记[Ppt]Java Jdk6学习笔记[Ppt]
Java Jdk6学习笔记[Ppt]yiditushe
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geekJohnson Gau
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代scott liao
 
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...Shengyou Fan
 
HTML5概览
HTML5概览HTML5概览
HTML5概览Adam Lu
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践yiditushe
 
第1讲 开始编写程序
第1讲 开始编写程序第1讲 开始编写程序
第1讲 开始编写程序ruandao
 
Kindeditor设计思路v2
Kindeditor设计思路v2Kindeditor设计思路v2
Kindeditor设计思路v2luolonghao
 
Google App Engine Devfest 200810 External
Google App Engine Devfest 200810 ExternalGoogle App Engine Devfest 200810 External
Google App Engine Devfest 200810 Externaljunyu
 

Similar to Page Object in XCUITest (20)

Go语言web开发
Go语言web开发Go语言web开发
Go语言web开发
 
Kind editor设计思路
Kind editor设计思路Kind editor设计思路
Kind editor设计思路
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
 
Golang
GolangGolang
Golang
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计
 
react-zh-hant.pdf
react-zh-hant.pdfreact-zh-hant.pdf
react-zh-hant.pdf
 
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
 
行動平台上利用Facebook API開發社群應用程式
行動平台上利用Facebook API開發社群應用程式行動平台上利用Facebook API開發社群應用程式
行動平台上利用Facebook API開發社群應用程式
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文
 
Kindeditor 设计思路
Kindeditor 设计思路Kindeditor 设计思路
Kindeditor 设计思路
 
Java Jdk6学习笔记[Ppt]
Java Jdk6学习笔记[Ppt]Java Jdk6学习笔记[Ppt]
Java Jdk6学习笔记[Ppt]
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
 
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
 
HTML5概览
HTML5概览HTML5概览
HTML5概览
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践
 
第1讲 开始编写程序
第1讲 开始编写程序第1讲 开始编写程序
第1讲 开始编写程序
 
Kindeditor设计思路v2
Kindeditor设计思路v2Kindeditor设计思路v2
Kindeditor设计思路v2
 
Google App Engine Devfest 200810 External
Google App Engine Devfest 200810 ExternalGoogle App Engine Devfest 200810 External
Google App Engine Devfest 200810 External
 

Page Object in XCUITest

  • 1.
  • 2. 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
  • 3. Overview • Introduce Page Object Pattern • Implement Page Classes (Swift 2.3) • Strategies and Tricks • Encountered Problems • Q & A
  • 4. What is Page Object? Reference by Martin Fowler
  • 6. Cases in manual test • Case1: • Home → Chat with people → Say “Hello” • Case2: • Home → Swipe to delete message Facebook Messenger
  • 8. 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”
  • 9. 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
  • 11. 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”
  • 12. 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
  • 13. 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
  • 14. 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?
  • 15. 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?
  • 16. So, What is Page Object? Reference by Martin Fowler
  • 17. The advantage of Page Object Easy to maintain Easy to read code Reduce Duplicate code
  • 18. Page
  • 19. Page
  • 20. Page
  • 21. Page
  • 22. Page
  • 23. Tab Bar Home Page Calls Page Group Page People Page Me Page
  • 24.
  • 25. How to know if is on this page or element ready? Wait
  • 26. Wait
  • 27. Wait for page loaded import XCTest class Page { static let app = XCUIApplication() private func waitForPageLoaded() { } required init() { waitForPageLoaded() } }
  • 28. Predicate class 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
  • 29. func testChatWithPeople() { let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello") XCTAssertEqual(chatRoomPage.leatestMessage, "Hello") } Reduce duplicate code app.cells[“Nadia”].tap()
  • 30. 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() }
  • 31. func testChatWithPeople() { let chatRoomPage = homePage.chat(with: "Nadia").sendMessage("Hello") XCTAssertEqual(chatRoomPage.leatestMessage, "Hello") } Reduce duplicate code app.textFields["Your message"].typeText("Hello")
  • 32. 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() }
  • 33. 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
  • 34. Page Object Pattern Chat Room Page send message Home Page chat back People Page chat go to people page Search Page go to search page search go to search page
  • 35. Strategies & Tricks • Protocol Extensions • Tab Bar • Search Bar • Generics • Go Back • Go To Different Page
  • 37. Tab Bar protocol MessengerTabBar { func goToHomePage() -> HomePage func goToCallsPage() -> CallsPage func goToGroupsPage() -> GroupsPage func goToPeoplePage() -> PeoplePage func goToMePage() -> MePage }
  • 38. Tab Bar protocol MessengerTabBar { // ... } extension MessengerTabBar { private var homeButton: XCUIElement { return Page.app.buttons["Home"] } // ... func goToHomePage() -> HomePage { homeButton.tap() return HomePage() } // ... }
  • 39. Tab Bar final class HomePage: Page, MessengerTabBar { // ... } HomePage
  • 40. let homePage = HomePage() homePage.gotoGroupsPage() .gotoMePage()
  • 41. let homePage = HomePage() homePage.goToGroupsPage() .gotoMePage()
  • 42. let homePage = HomePage() homePage.goToGroupsPage() .goToMePage()
  • 43. Protocol Extensions • There are have MessengerSearchBar
  • 44. Protocol Extensions Chat Room Page send message Home Page chat back People Page chat go to people page Search Page go to search page search go to search page
  • 45. Protocol Extensions final class HomePage: Page, MessengerTabBar, MessengerSearchBar { // ... } final class GroupsPage: Page, MessengerTabBar, MessengerSearchBar { // ... } final class MePage: Page, MessengerTabBar, MessengerSearchBar { // ... } final class PeoplePage: Page, MessengerTabBar, MessengerSearchBar { // ... }
  • 46. Back
  • 48. Back Chat Room Page send message Home Page chat back People Page chat go to people page Search Page go to search page search go to search page
  • 49. 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
  • 50. 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
  • 51. HomePage ChatRoomPage 1. chat(with:" ") 2. backTo(HomePage) homePage.chat(with:" ").backTo(HomePage)
  • 52. Taps the same button, but it could go to different page Generics Can we return two page classes !?
  • 53. Generics Tap play button Possible 1 Go to Nowplaying page Possible 2 Go to Chart page
  • 54. Generics func 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)
  • 56. Sets Element Accessibility • Accessibility data makes UI testing possible Reference: UI Testing in Xcode - WWDC 2015 - Videos - Apple Developer Testability Quality of Accessibility Data
  • 57. Speed Up Testing • Set launch arguments to speed up testing Tutorial View
  • 58. Speed Up Testing override 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
  • 59. Reduce Motion • UI animation might cause test fail while transit
  • 60. 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
  • 61. Turn Off Auto-Correction • Input string might be changed • Settings > General > Keyboards
  • 62. Slow Network Speed • Using Network Link Conditioner tool to restrict network speed. (For simulator)
  • 63. Software Update • Don’t remind me to upgrade iOS ( Tutorial Link )
  • 64. 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
  • 65.
  • 66. Q & A • Q: ⼤概你們就是把⼀個,⽤ state machine 的概念,配合 IoC 反轉注⼊ 的概念,把這個精神套⼊到你的 UI test 這個精神、這個動作上⾯。那 我想要問的就是,你們費了這麼多功夫,實現了這個 page object,你 覺得它有什麼缺點,會不會變成說你做了⼀個這麼精緻的 page object 的 test,會不會變成我還要再寫⼀個測試程式去測這個測試程式? • A: (Mark) Page object ⽬前我們實作起來,看起來是 ... 缺點來說 我到 ⽬前都覺得滿順利的,因為我們⼀開始在實作的時候,其實都是⽤ 直接 點元件 這樣點 這樣點 然後就其實也看不出來測試到底在測試什麼東 西,然後你再包裝成 page object 的話,就可讀性都⽐較⾼,⾄於說包 裝起來是不是要測試,我們⽬前是沒有這⼀層的測試,不然這樣其實也 測不完,所以我們這部份是沒有再繼續對 page object 這個 pattern 去 做測試。
  • 67. 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 要不要上⼀下? 做決定的⼈在這裡...)
  • 68. 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,也都有這⽅⾯的好處。
  • 69. 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 然後在上⾯執 ⾏。
  • 70. 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