Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift Techniques for Testing

B001c3f62d78ea6b95286d343eb7c978?s=47 Kaya Thomas
February 03, 2020

Swift Techniques for Testing

This talk explains two unique techniques to help make your tests easier to read, write and understand. The first technique is using Swift enums to abstract XCUIElementQuery calls and to isolate UI element into cases with each enum representing one screen. The second technique uses function builders to allow you to group multiple calls to XCTAssertTrue() and XCTAssertFalse().

B001c3f62d78ea6b95286d343eb7c978?s=128

Kaya Thomas

February 03, 2020
Tweet

Transcript

  1. Swift Techniques for Testing Kaya Thomas dotSwift 2020

  2. How can we make our tests easier to write, easier

    to understand and less prone to developer errors?
  3. • Using enums with UI tests • Function builders with

    XCTAssert @kthomas901 dotSwift2020
  4. • Using enums with UI tests • Function builders with

    XCTAssert @kthomas901 dotSwift2020
  5. Example app @kthomas901 dotSwift2020

  6. @kthomas901 dotSwift2020

  7. Features @kthomas901 dotSwift2020

  8. Features • Comparing three currencies to one base currency @kthomas901

    dotSwift2020
  9. Features • Comparing three currencies to one base currency •

    Ability to change which currency is used for the base currency @kthomas901 dotSwift2020
  10. Features • Comparing three currencies to one base currency •

    Ability to change which currency is used for the base currency • Ability to enter the amount of money for the currency conversions @kthomas901 dotSwift2020
  11. Features • Comparing three currencies to one base currency •

    Ability to change which currency is used for the base currency • Ability to enter the amount of money for the currency conversions • Display the names of each country’s currency with their flags @kthomas901 dotSwift2020
  12. UI Testing with XCTestCase Search for existing UI elements on

    the XCUIApplication using: XCUIElementQuery
  13. UI Testing with XCTestCase Search for existing UI elements on

    the XCUIApplication using: XCUIElementQuery Example to find a label with the text “Hello World”: XCUIApplication().staticTexts[“Hello World”]
  14. Testing initial state func testInitialState() { XCTAssertTrue(app.staticTexts["Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States

    Dollar"].exists) XCTAssertTrue(app.textFields["1"].exists) } @kthomas901 dotSwift2020
  15. Testing initial state func testInitialState() { XCTAssertTrue(app.staticTexts[“Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States

    Dollar"].exists) XCTAssertTrue(app.textFields["1"].exists) } @kthomas901 dotSwift2020 XCTAssertTrue(app.staticTexts["Base Currency"].exists)
  16. Testing initial state func testInitialState() { XCTAssertTrue(app.staticTexts[“Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States

    Dollar"].exists) XCTAssertTrue(app.textFields["1"].exists) } @kthomas901 dotSwift2020 XCTAssertTrue(app.staticTexts["United States Dollar"].exists)
  17. Testing initial state func testInitialState() { XCTAssertTrue(app.staticTexts["Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States

    Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists) } @kthomas901 dotSwift2020 XCTAssertTrue(app.staticTexts["United States Dollar"].exists)
  18. Testing initial state func testInitialState() { XCTAssertTrue(app.staticTexts["Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States

    Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists) } @kthomas901 dotSwift2020 XCTAssertTrue(app.textFields["1"].exists)
  19. Let’s capture our screen UI in an enum enum AppUI:

    String { case baseCurrencyView = "Base Currency" case unitedStatesDollarView = "United States Dollar" case euroView = "Euro" case canadianDollarView = "Canadian Dollar" case francView = "Franc" case initialTextField = "1" } @kthomas901 dotSwift2020
  20. Extending our enum extension AppUI { var isStaticText: Bool {

    return XCUIApplication().staticTexts[self.rawValue].exists } var isTextField: Bool { return XCUIApplication().textFields[self.rawValue].exists } }
  21. Revisiting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.staticTexts[“Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists)
  22. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.staticTexts[“Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists)
  23. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.staticTexts[“Base Currency"].exists) XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists)
  24. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists) XCTAssertTrue(AppUI.baseCurrencyView.isStaticText)
  25. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertTrue(app.textFields[“1"].exists) XCTAssertTrue(AppUI.baseCurrencyView.isStaticText)
  26. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.textFields[“1"].exists) XCTAssertTrue(AppUI.baseCurrencyView.isStaticText) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText)
  27. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(app.textFields[“1"].exists) XCTAssertTrue(AppUI.baseCurrencyView.isStaticText) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText)
  28. Rewriting initial state test func testInitialState() { } @kthomas901 dotSwift2020

    XCTAssertTrue(AppUI.baseCurrencyView.isStaticText) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.initialTextField.isTextField)
  29. Testing functionality @kthomas901 dotSwift2020

  30. Testing functionality @kthomas901 dotSwift2020

  31. Without using the enum func testUpdatingBaseCurrencyCell() { XCTAssertTrue(app.staticTexts["United States Dollar"].exists)

    XCTAssertFalse(app.staticTexts["Euro"].exists) app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) } @kthomas901 dotSwift2020
  32. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertFalse(app.staticTexts["Euro"].exists) app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists)
  33. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    XCTAssertTrue(app.staticTexts["United States Dollar"].exists) XCTAssertFalse(app.staticTexts["Euro"].exists) app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists)
  34. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    XCTAssertFalse(app.staticTexts["Euro"].exists) app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText)
  35. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    XCTAssertFalse(app.staticTexts["Euro"].exists) app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText)
  36. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    XCTAssertFalse(app.staticTexts["Euro"].exists) app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText)
  37. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertFalse(AppUI.euroView.isStaticText)
  38. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertFalse(AppUI.euroView.isStaticText)
  39. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(app.staticTexts["Euro"].exists) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertFalse(AppUI.euroView.isStaticText)
  40. Testing functionality using enum @kthomas901 dotSwift2020 func testUpdatingBaseCurrencyCell() { }

    app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertFalse(AppUI.euroView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText)
  41. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } }
  42. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists }
  43. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var element: XCUIElement { } if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] }
  44. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var element: XCUIElement { } if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] }
  45. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var element: XCUIElement { } } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] }
  46. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var element: XCUIElement { } } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] }
  47. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var element: XCUIElement { } } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError()
  48. Adding to the enum @kthomas901 dotSwift2020 extension AppUI { var

    isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists } var element: XCUIElement { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() } } var element: XCUIElement { } } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError()
  49. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText) }

    @kthomas901 dotSwift2020 XCTAssertFalse(AppUI.euroView.isStaticText) app.tables.cells.element(boundBy: 0).tap()
  50. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText) }

    @kthomas901 dotSwift2020 XCTAssertFalse(AppUI.euroView.isStaticText) app.tables.cells.element(boundBy: 0).tap()
  51. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText) }

    @kthomas901 dotSwift2020 XCTAssertTrue(AppUI.euroView.isWithinTableCell) app.tables.cells.element(boundBy: 0).tap()
  52. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText) }

    @kthomas901 dotSwift2020 app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(AppUI.euroView.isWithinTableCell)
  53. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText) }

    @kthomas901 dotSwift2020 app.tables.cells.element(boundBy: 0).tap() XCTAssertTrue(AppUI.euroView.isWithinTableCell)
  54. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.euroView.isStaticText) }

    @kthomas901 dotSwift2020 XCTAssertTrue(AppUI.euroView.isWithinTableCell) AppUI.euroView.element.tap()
  55. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) AppUI.euroView.element.tap() XCTAssertTrue(AppUI.euroView.isStaticText)

    } @kthomas901 dotSwift2020 XCTAssertTrue(AppUI.euroView.isWithinTableCell)
  56. Revisiting the functionality test func testUpdatingBaseCurrencyCell() { XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) AppUI.euroView.element.tap() XCTAssertTrue(AppUI.euroView.isStaticText)

    } @kthomas901 dotSwift2020 XCTAssertTrue(AppUI.euroView.isWithinTableCell) XCTAssertTrue(AppUI.unitedStatesDollarView.isWithinTableCell)
  57. Creating an ElementType enum enum ElementType { case textField case

    staticText case tableCellButton init?(_ text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020
  58. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 case textField case staticText case tableCellButton
  59. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 init?(_ text: String) { if XCUIApplication().textFields[text].exists { self = .textField } }
  60. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 init?(_ text: String) { if XCUIApplication().textFields[text].exists { self = .textField } }
  61. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 init?(_ text: String) { } } else if XCUIApplication().staticTexts[text].exists { self = .staticText }
  62. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 init?(_ text: String) { } } else if XCUIApplication().staticTexts[text].exists { self = .staticText }
  63. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 init?(_ text: String) { } } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil }
  64. enum ElementType { case textField case staticText case tableCellButton init?(_

    text: String) { if XCUIApplication().textFields[text].exists { self = .textField } else if XCUIApplication().staticTexts[text].exists { self = .staticText } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil } } } @kthomas901 dotSwift2020 init?(_ text: String) { } } else if XCUIApplication().tables.cells.buttons[text].exists { self = .tableCellButton } else { return nil }
  65. Get XCUIElement from ElementType extension AppUI { var element: XCUIElement

    { if self.isStaticText { return XCUIApplication().staticTexts[self.rawValue] } else if self.isTextField { return XCUIApplication().textFields[self.rawValue] } else if self.isWithinTableCell { return XCUIApplication().tables.cells.buttons[self.rawValue] } fatalError() }
  66. Get XCUIElement from ElementType extension ElementType { func getElement(with text:

    String) -> XCUIElement { switch self { case .staticText: return XCUIApplication().staticTexts[text] case .textField: return XCUIApplication().textFields[text] case .tableCellButton: return XCUIApplication().tables.cells.buttons[text] } } }
  67. Using ElementType extension AppUI { var type: ElementType { guard

    let type = ElementType(self.rawValue) else { fatalError() } return type } var element: XCUIElement { return type.getElement(with: self.rawValue) } }
  68. Using ElementType @kthomas901 dotSwift2020 extension AppUI { } var isStaticText:

    Bool { return XCUIApplication().staticTexts[self.rawValue].exists } var isTextField: Bool { return XCUIApplication().textFields[self.rawValue].exists } var isWithinTableCell: Bool { return XCUIApplication().tables.cells.buttons[self.rawValue].exists }
  69. Using ElementType @kthomas901 dotSwift2020 extension AppUI { } var isStaticText:

    Bool { return type == .staticText } var isTextField: Bool { return type == .textField } var isWithinTableCell: Bool { return type == .tableCellButton }
  70. Recap @kthomas901 dotSwift2020

  71. Recap • Use the enum cases to represent the different

    elements on one screen @kthomas901 dotSwift2020
  72. Recap • Use the enum cases to represent the different

    elements on one screen • Have a computed variable for the element in your enum that you can take actions on @kthomas901 dotSwift2020
  73. Recap • Use the enum cases to represent the different

    elements on one screen • Have a computed variable for the element in your enum that you can take actions on @kthomas901 dotSwift2020 • Create a separate ElementType enum that can be reused for the different enums you have for each screen
  74. • Using enums with UI tests • Function builders with

    XCTAssert @kthomas901 dotSwift2020
  75. Function builders Swift 5.1 @kthomas901 dotSwift2020

  76. @kthomas901 dotSwift2020

  77. func testInitialState() { XCTAssertTrue(AppUI.baseCurrencyView.isStaticText) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.initialTextField.isTextField) } Before: @kthomas901 dotSwift2020

  78. func testInitialState() { XCTAssertTrue(AppUI.baseCurrencyView.isStaticText) XCTAssertTrue(AppUI.unitedStatesDollarView.isStaticText) XCTAssertTrue(AppUI.initialTextField.isTextField) } func testInitialState() {

    assertTrue { AppUI.baseCurrencyView.isStaticText AppUI.unitedStatesDollarView.isStaticText AppUI.initialTextField.isTextField } } Before: After: @kthomas901 dotSwift2020
  79. BooleanFunctionBuilder @_functionBuilder class BooleanFunctionBuilder { static func buildBlock(_ children: Bool...)

    -> [Bool] { return children } } @kthomas901 dotSwift2020
  80. Grouping XCAssertTrue & XCAssertFalse @kthomas901 dotSwift2020

  81. Grouping XCAssertTrue & XCAssertFalse public func assertTrue(@BooleanFunctionBuilder builder: () ->

    [Bool]) { let expressions = builder() expressions.forEach { XCTAssertTrue($0) } } @kthomas901 dotSwift2020
  82. Grouping XCAssertTrue & XCAssertFalse public func assertTrue(@BooleanFunctionBuilder builder: () ->

    [Bool]) { let expressions = builder() expressions.forEach { XCTAssertTrue($0) } } public func assertFalse(@BooleanFunctionBuilder builder: () -> [Bool]) { let expressions = builder() expressions.forEach { XCTAssertFalse($0) } } @kthomas901 dotSwift2020
  83. Using assertTrue

  84. Using assertTrue func testInitialState() { assertTrue { AppUI.baseCurrencyView.isStaticText AppUI.unitedStatesDollarView.isStaticText AppUI.initialTextField.isTextField

    } }
  85. Recap @kthomas901 dotSwift2020

  86. Recap • Function builders help make your code more readable

    and easier to write @kthomas901 dotSwift2020
  87. Recap • Function builders help make your code more readable

    and easier to write • They can be really simple! @kthomas901 dotSwift2020
  88. Resources • iOS Automation with XCUITest, free course at Test

    Automation U by Shashikant Jagtap • Testing Swift by Paul Hudson • Awesome Function Builders Github repo @kthomas901 dotSwift2020
  89. Thank you!