cocoaheads • aug 2018 ui tdd tdd · 2019-05-24 · cocoaheads • aug 2018 tdd. software testing....

Post on 20-Jun-2020

6 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

UI TDDCOCOAHEADS • AUG 2018

TDD

UI TDDCOCOAHEADS • AUG 2018

TDD

SOFTWARE TESTING

SOFTWARE TESTING

SOFTWARE TESTINGRepeatability

SOFTWARE TESTINGRepeatability

🙏

INFORMAL MANUAL TESTING

SOFTWARE TESTINGRepeatability

🙏

INFORMAL MANUAL TESTING

📋

FORMAL MANUAL TESTING

SOFTWARE TESTINGRepeatability

🙏

INFORMAL MANUAL TESTING

📋

FORMAL MANUAL TESTING

🤖

AUTOMATEDTESTING

SOFTWARE TESTINGAUTOMATED

UNITINPUT OUTPUT

SOFTWARE TESTINGAUTOMATED

UNIT

SOFTWARE TESTINGAUTOMATED

SOFTWARE TESTINGAUTOMATED

INTEGRATION

SOFTWARE TESTINGAUTOMATED

SOFTWARE TESTINGAUTOMATED

END-TO-END

SOFTWARE TESTINGAUTOMATED

END-TO-ENDINTEGRATIONUNIT

SOFTWARE TESTINGAUTOMATED

END-TO-ENDINTEGRATIONUNIT

SOFTWARE TESTINGAUTOMATEDTime/Complexity

END-TO-ENDINTEGRATIONUNIT

SOFTWARE TESTINGAUTOMATEDTime/Complexity

Realism

END-TO-ENDINTEGRATIONUNIT

SOFTWARE TESTINGAUTOMATED

END-TO-ENDINTEGRATIONUNIT

Time/ComplexityRealism

📲 UI TESTS

UI TESTS

UI TESTS

UI TESTS

UI TESTS

UI TESTS

UI TESTS

UI TESTS

%

VERIFY BEHAVIOR

UI TESTS

BUILT ON ACCESSIBILITY

%

VERIFY BEHAVIOR

UI TESTS

%

VERIFY BEHAVIOR

BUILT ON ACCESSIBILITY

RECORD TO LEARN

BETTER UI TESTING

BETTER UI TESTING

BETTER UI TESTING

BETTER UI TESTING

Title

BETTER UI TESTING

Button

Title

BETTER UI TESTING

Button

Title

Table

BETTER UI TESTING

Button

Title

Cell

Table

BETTER UI TESTING

Button

ButtonTitle

Cell

Table

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

BETTER UI TESTING

Button

Button

Table

Button

Title

Cell

BETTER UI TESTING

Button

Button

Table

TitleButton

Title

Cell

BETTER UI TESTING

Button

Button

Table

Title

Label

Button

Title

Cell

BETTER UI TESTING

Button

Button

Table

Button

Title

Label

Button

Title

Cell

BETTER UI TESTING

Button

Button

Table

Button

Title

Label

Button

Title

Cell

BETTER UI TESTING

Button

Button

Table

Button

Title

Label

TapButton

Title

Cell

BETTER UI TESTING

Button

Button

Table

Button

Title

Label

TapButton

Title

CellSwipe

BETTER UI TESTING

Button

Button

Table

Button

Title

Label

Tap

Tap

Button

Title

CellSwipe

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

Text

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText

Text

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText

Text

Text

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText Text

Text

Text

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText Text

Title

Text

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText Text

Title

Text

BETTER UI TESTING

Button

Button

Button

Title

Cell

Table

Button

Title

Label

Tap

Tap

Tap

Swipe

Tap

Tap

CountText Text

Title

Text

BENEFITS

BENEFITS

&

EASIER TO READ

BENEFITS

XCUIApplication().tables.children(matching: .cell).element(boundBy: 0).staticTexts["2018-07-03 20:45:14 +0000"].tap()

Before

&

EASIER TO READ

BENEFITS

.tapOnCell(at: 0)

Before

After

XCUIApplication().tables.children(matching: .cell).element(boundBy: 0).staticTexts["2018-07-03 20:45:14 +0000"].tap()

&

EASIER TO READ

BENEFITS

&

EASIER TO READ

'

EASIER TO MAINTAIN

BENEFITS

&

EASIER TO READ

'

EASIER TO MAINTAIN

(

WRITE TESTS FIRST!

&

EASIER TO READ

BENEFITS

'

EASIER TO MAINTAIN

TDD

(

WRITE TESTS FIRST!

TDDTEST-DRIVEN DEVELOPMENT

TDD

)

TDD

)

TDD

()

TDD

()

TDD

()

TDD

()

TDD

()

TDD

()

TDD

()

TDD

()

TDD

{

}

{

}

()

TDD

{

}

{

}

()

CODE

CODE

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

// MARK: - Actions // MARK: - Verifications

}

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

// MARK: - Actions // MARK: - Verifications

}

import XCTest

protocol TestPage { var testCase: XCTestCase { get }}

extension TestPage { var app: XCUIApplication { return XCUIApplication() } }

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

// MARK: - Actions // MARK: - Verifications

}

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

// MARK: - Actions // MARK: - Verifications

}

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] } fileprivate var backButton: XCUIElement { return app.navigationBars.buttons["Master"] } ...

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] } fileprivate var backButton: XCUIElement { return app.navigationBars.buttons["Master"] } ...

Button

Label

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] } fileprivate var backButton: XCUIElement { return app.navigationBars.buttons["Master"] } ...

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

}

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] } fileprivate var backButton: XCUIElement { return app.navigationBars.buttons["Master"] } ...

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

}

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] } fileprivate var backButton: XCUIElement { return app.navigationBars.buttons["Master"] } ...

CODE

import XCTest

struct DetailPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

}

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] } fileprivate var backButton: XCUIElement { return app.navigationBars.buttons["Master"] } ...

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

Tap

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

CODE

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

CODE

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

CODE

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

...

func expect(exists element: XCUIElement, file: String = #file, line: UInt = #line) { if !element.exists { recordFailure(withDescription: "Expected \(element) to exist.", inFile: file, atLine: Int(line), expected: true) } }

...

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

...

func expect(exists element: XCUIElement, file: String = #file, line: UInt = #line) { if !element.exists { recordFailure(withDescription: "Expected \(element) to exist.", inFile: file, atLine: Int(line), expected: true) } }

...

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

...

func expect(exists element: XCUIElement, file: String = #file, line: UInt = #line) { if !element.exists { recordFailure(withDescription: "Expected \(element) to exist.", inFile: file, atLine: Int(line), expected: true) } }

...

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

...

func expect(exists element: XCUIElement, file: String = #file, line: UInt = #line) { if !element.exists { recordFailure(withDescription: "Expected \(element) to exist.", inFile: file, atLine: Int(line), expected: true) } }

...

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

...

func expect(exists element: XCUIElement, file: String = #file, line: UInt = #line) { if !element.exists { recordFailure(withDescription: "Expected \(element) to exist.", inFile: file, atLine: Int(line), expected: true) } }

...

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

CODE

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

@discardableResult func tapOnBackButton(file: StaticString = #file, line: UInt = #line) -> MasterPage { XCTAssertTrue(backButton.exists, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

... }

CODE

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

@discardableResult func tapOnBackButton(file: StaticString = #file, line: UInt = #line) -> MasterPage { XCTAssertTrue(backButton.exists, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

... }

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

import XCTest

struct DetailPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func tapOnBackButton(file: String = #file, line: UInt = #line) -> MasterPage { testCase.expect(exists: backButton, file: file, line: line) backButton.tap() return MasterPage(testCase: testCase) }

CODE

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file:

CODE

// MARK: - Elements

fileprivate var detailText: XCUIElement { return app.staticTexts[“DetailViewController.label"] }

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

Text

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

CODE

...

// MARK: - Verifications @discardableResult func verifyDetailPageIsShowing(file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) return self } @discardableResult func verifyLabelText(is text: String, file: String = #file, line: UInt = #line) -> DetailPage { testCase.expect(exists: detailText, file: file, line: line) testCase.expect(detailText.label, equals: text, file: file, line: line) return self } ... }

CODE

CODE

CODE

import XCTest

class BasicEntryUITests: XCTestCase {

}

CODE

import XCTest

class BasicEntryUITests: XCTestCase { override func setUp() { super.setUp() continueAfterFailure = false let application = XCUIApplication() application.launchArguments.append("--uitesting") application.launch() }

}

CODE

import XCTest

class BasicEntryUITests: XCTestCase { override func setUp() { super.setUp() continueAfterFailure = false let application = XCUIApplication() application.launchArguments.append("--uitesting") application.launch() }

}

CODE

import XCTest

class BasicEntryUITests: XCTestCase { override func setUp() { super.setUp() continueAfterFailure = false let application = XCUIApplication() application.launchArguments.append("--uitesting") application.launch() }

}

CODE

super.setUp() continueAfterFailure = false let application = XCUIApplication() application.launchArguments.append("--uitesting") application.launch() }

}

class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { if CommandLine.arguments.contains("--uitesting") { // Set up state for UI testing } ... } }

CODE

super.setUp() continueAfterFailure = false let application = XCUIApplication() application.launchArguments.append("--uitesting") application.launch() }

}

class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { if CommandLine.arguments.contains("--uitesting") { // Set up state for UI testing } ... } }

CODE

import XCTest

class BasicEntryUITests: XCTestCase { override func setUp() { super.setUp() continueAfterFailure = false let application = XCUIApplication() application.launchArguments.append("--uitesting") application.launch() }

}

CODE

... func testAddingEntry() {

}

...

CODE

... func testAddingEntry() { MasterPage(testCase: self)

}

...

CODE

... func testAddingEntry() { MasterPage(testCase: self) .verifyMasterPageIsShowing()

}

...

CODE

... func testAddingEntry() { MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0)

}

...

CODE

... func testAddingEntry() { MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton()

}

...

CODE

... func testAddingEntry() { MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1)

}

...

CODE

... func testAddingEntry() { MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: )

}

...

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel)

}

...

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0)

}

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing()

}

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: nowLabel)

}

...

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: nowLabel) .tapOnBackButton()

}

...

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: nowLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: nowLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

CODE

... func testAddingEntry() { let nowLabel = String(describing: Date()) MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: nowLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: nowLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

Expected ‘Optional(…

CODE

... func testAddingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: zeroLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

CODE

... func testAddingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: zeroLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

CODE

... func testAddingAndDeletingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: zeroLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

CODE

... func testAddingAndDeletingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: zeroLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

import XCTest

struct MasterPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate func cell(at index: Int) -> XCUIElement { return table.cells.element(boundBy: index)} fileprivate func deleteButton(for cell: XCUIElement) -> XCUIElement { return cell.buttons["Delete"]} ...

import XCTest

struct MasterPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate func cell(at index: Int) -> XCUIElement { return table.cells.element(boundBy: index)} fileprivate func deleteButton(for cell: XCUIElement) -> XCUIElement { return cell.buttons["Delete"]} ...

Button

import XCTest

struct MasterPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate func cell(at index: Int) -> XCUIElement { return table.cells.element(boundBy: index)} fileprivate func deleteButton(for cell: XCUIElement) -> XCUIElement { return cell.buttons["Delete"]} ...

import XCTest

struct MasterPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate func cell(at index: Int) -> XCUIElement { return table.cells.element(boundBy: index)} fileprivate func deleteButton(for cell: XCUIElement) -> XCUIElement { return cell.buttons["Delete"]} ...

import XCTest

struct MasterPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate func cell(at index: Int) -> XCUIElement { return table.cells.element(boundBy: index)} fileprivate func deleteButton(for cell: XCUIElement) -> XCUIElement { return cell.buttons["Delete"]} ...

import XCTest

struct MasterPage: TestPage { let testCase: XCTestCase

// MARK: - Elements

} CODE

fileprivate func cell(at index: Int) -> XCUIElement { return table.cells.element(boundBy: index)} fileprivate func deleteButton(for cell: XCUIElement) -> XCUIElement { return cell.buttons["Delete"]} ...

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

Tap

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

import XCTest

struct MasterPage: TestPage { ...

// MARK: - Actions

... }

@discardableResult func deleteCell(at index: Int, file: String = #file, line: UInt = #line) -> MasterPage { let cell = self.cell(at: index) testCase.expect(exists: cell, file: file, line: line) cell.swipeLeft() let deleteButton = self.deleteButton(for: cell) testCase.expect(exists: deleteButton, file: file, line: line) deleteButton.tap() return self}

CODE

CODE

... func testAddingAndDeletingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) // Detail page .verifyDetailPageIsShowing() .verifyLabelText(is: zeroLabel) .tapOnBackButton() // Master page .verifyMasterPageIsShowing() }

...

CODE

... func testAddingAndDeletingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) ... // Master page .verifyMasterPageIsShowing()

}

...

CODE

... func testAddingAndDeletingEntry() { let zeroLabel = "0" MasterPage(testCase: self) .verifyMasterPageIsShowing() .verifyTableCellCount(is: 0) .tapOnAddButton() .verifyTableCellCount(is: 1) .verifyCell(at: 0, hasLabel: zeroLabel) .tapOnCell(at: 0) ... // Master page .verifyMasterPageIsShowing() .verifyTableCellCount(is: 1) .deleteCell(at: 0) .verifyTableCellCount(is: 0) }

...

TIPS & TRICKS

TIPS & TRICKS

WWDC2018Testing Tips & Tricks🎞2017Engineering for Testability

🎞

TIPS & TRICKS

📼

LOCAL DATA

TIPS & TRICKS

📼

LOCAL DATA

🚫

AVOID DUPLICATION

TIPS & TRICKS

📼

LOCAL DATA

🚫

AVOID DUPLICATION

USE MULTIPLE SCHEMES

GETTING STARTED

GETTING STARTED

📰

NEXT BUG/FEATURE

GETTING STARTED

🔑

IMPORTANT FREQUENT

📰

NEXT BUG/FEATURE

GETTING STARTED

🔑

IMPORTANT FREQUENT

IMPORTANT INFREQUENT

📰

NEXT BUG/FEATURE

SUMMARY

SOFTWARE TESTINGAUTOMATED

END-TO-ENDINTEGRATIONUNIT

UI TESTS

%

VERIFY BEHAVIOR

BUILT ON ACCESSIBILITY

RECORD TO LEARN

TDD

{

}

{

}

()

UI TDDCOCOAHEADS • AUG 2018

1 //BSN.DESIGN

TDD

top related