Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
XCUITest by PageObjectPattern
Search
lcr3
October 30, 2020
Programming
57
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
XCUITest by PageObjectPattern
社内向け勉強会資料
煩雑になっていらUIXCTestをPageObjectPatternに沿ってリファクタしたお話
lcr3
October 30, 2020
More Decks by lcr3
See All by lcr3
VIPER
lcr3
0
110
アプリエンジニアになるには
lcr3
0
40
Other Decks in Programming
See All in Programming
Web Framework Benchmark Battle 2026, Any%
a_matsuda
2
2.2k
Vue Fes Japan の “作る側”に関わってみて
naokihaba
0
160
ActionController meets Protocol Buffers
sorah
0
540
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
500
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.9k
AWS CDKのカスタムリソースでContinuum(旧Security Agent)を実装した話 | Implementing Continuum (formerly Security Agent) via AWS CDK Custom Resource
akihisaikeda
2
150
自サークルのIdPからログアウトできるようになるまで
taiseiue
1
140
AmebaブログはKMPから卒業します
kmars0605
0
200
カツオ、ご期待ください
suneo3476
0
190
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
180
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
2
740
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
290
Featured
See All Featured
Reflections from 52 weeks, 52 projects
jeffersonlam
356
22k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.7k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
520
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.7k
Bash Introduction
62gerente
615
220k
First, design no harm
axbom
PRO
2
1.3k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
5
820
RailsConf 2023
tenderlove
30
1.6k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
7k
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
580
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
530
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
2
6.3k
Transcript
Page Object Pattern UITestΛϦϑΝΫλͨ͠
UITestͷ • ͳίʔυ͕૿͑Δ • ڊେԽ • ಡΈʹ͍͘
Page Object Pattern
ςετର • ΞϓϦΛىಈ • ID, PasswordΛೖྗ͢Δ • ϩάΠϯϘλϯΛλοϓ͢Δ • ϩάΠϯ͕ޭ͠ը໘͕ભҠ͍ͯ͠Δ͔֬ೝ͢Δ
// 1-2 ίϯλΫτIDͱύεϫʔυΛೖྗͯ͠ϩάΠϯͰ͖Δ func testLogin() { let loginIDField = app.textFields["ϩάΠϯID"]
let passwordField = app.secureTextFields["ύεϫʔυ"] let defaultLoginIDPlaceholder = "ϩάΠϯID" let defaultPasswordPlaceholder = "ύεϫʔυ" let inputLoginId = "999000000000" let inputPassword = “password" let deleteButtonLabel = "ςΩετΛফڈ" let loginButtonLabel = "ϩάΠϯ" let contactlistViewControllerTitleLabel = "SelfNameLabel" loginIDField.tap() // ϩάΠϯCIDςΩετϑΟʔϧυΛλοϓ if let loginId = loginIDField.value as? String, loginId != defaultLoginIDPlaceholder { app.buttons[deleteButtonLabel].tap() // ͢ͰʹೖྗࡁΈͷ߹আ͢Δ } loginIDField.typeText(inputLoginId) // ϩάΠϯCIDΛೖྗ passwordField.tap() // ύεϫʔυςΩετϑΟʔϧυΛλοϓ͢Δ if let password = passwordField.value as? String, password != defaultPasswordPlaceholder { app.buttons[deleteButtonLabel].tap() // ͢ͰʹೖྗࡁΈͷ߹আ͢Δ } passwordField.typeText(inputPassword) // ύεϫʔυΛೖྗ app.buttons[loginButtonLabel].tap() // ϩάΠϯϘλϯΛλοϓ XCTAssert(app.staticTexts[contactlistViewControllerTitleLabel].exists) } ݱঢ়ͷςετίʔυ ςετͷ४උ ૢ࡞ ݕূ
ݱঢ়ͷ • ૢ࡞ίʔυͷҙਤ͕͔ΓͮΒ͍ • ςετέʔε͝ͱʹಉ͡Α͏ͳίʔυΛॻ͘Մೳੑ͕͋Δ
PageObjectPatter Λద༻ // 1-2 ίϯλΫτIDͱύεϫʔυΛೖྗͯ͠ϩάΠϯͰ͖Δ func testLogin() { // setup
let inputCid = "999000000000" let inputPassword = "password" // execute let contactList = LoginPage(app: app) .typeCid(inputCid) .typePassword(inputPassword) .tapLoginButton() // verify XCTxContext("ϩάΠϯ͕ޭ͠ɺൃ৴ը໘͕දࣔ͞Ε͍ͯΔ͜ͱ") { XCTAssertEqual(contactList.selfCidText, inputCid) } } ςετͷ४උ ૢ࡞ ݕূ
protocol Page { var app: XCUIApplication { get } init(app:
XCUIApplication) } class LoginPage: Page { let app: XCUIApplication required init(app: XCUIApplication) { self.app = app } } ४ڌ
class LoginPage: Page { // … private var cidTextField: XCUIElement
{ return app.textFields["LoginIdTextField"] } private var passwordTextField: XCUIElement { return app.secureTextFields["PasswordTextField"] } private var loginButton: XCUIElement { return app.buttons["LoginButton"] } private var deleteButton: XCUIElement { return app.buttons["ςΩετΛফڈ"] } } ࢀর࣌ʹຖճཁૉΛ୳͢Α͏ʹ͢ΔͨΊɺܭࢉܕͷϓϩύςΟͱͯͭ͠ Pageͷཁૉ
Pageͷϝιου class LoginPage: Page { // … func typeCid(_ inputCid:
String) -> LoginPage { cidTextField.tap() cidTextField.typeText(inputCid) return self } func typePassword(_ inputPassword: String) -> LoginPage { passwordTextField.tap() passwordTextField.typeText(inputPassword) return self } func tapLoginButton() -> ContactListPage { loginButton.tap() return ContactListPage() } }
·ͱΊ • ςετίʔυͰςετͷ༰͕Θ͔ΔΑ͏ʹॻ͘ • PageͷதͰ۩ମతͳૢ࡞Λॻ͘ • ૢ࡞ϝιουૢ࡞ޙͷPage Λฦ͢