Top Banner
116
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Quick: Better Tests via Incremental Setup
Page 2: Quick: Better Tests via Incremental Setup
Page 3: Quick: Better Tests via Incremental Setup

testing?

Page 4: Quick: Better Tests via Incremental Setup

does your app do what you think it does?

Page 5: Quick: Better Tests via Incremental Setup

how?

Page 6: Quick: Better Tests via Incremental Setup

run the app

Page 7: Quick: Better Tests via Incremental Setup
Page 8: Quick: Better Tests via Incremental Setup
Page 9: Quick: Better Tests via Incremental Setup

println()

Page 10: Quick: Better Tests via Incremental Setup

not that simple

Page 11: Quick: Better Tests via Incremental Setup

big app?

Page 12: Quick: Better Tests via Incremental Setup

working with others?

Page 13: Quick: Better Tests via Incremental Setup

works?

Page 14: Quick: Better Tests via Incremental Setup

manual testing doesn’t scale

Page 15: Quick: Better Tests via Incremental Setup

manual testing is vague

Page 16: Quick: Better Tests via Incremental Setup

automated tests are fast

Page 17: Quick: Better Tests via Incremental Setup

automated tests are precise

Page 18: Quick: Better Tests via Incremental Setup
Page 19: Quick: Better Tests via Incremental Setup
Page 20: Quick: Better Tests via Incremental Setup

testing apps is awesome

Page 21: Quick: Better Tests via Incremental Setup

testing apps is cool when you’re part of a team

Page 22: Quick: Better Tests via Incremental Setup

some tests are more awesome than others

Page 23: Quick: Better Tests via Incremental Setup

good tests are clear

Page 24: Quick: Better Tests via Incremental Setup

ARRANGE ACT

ASSERT

Page 25: Quick: Better Tests via Incremental Setup

ARRANGE ACT

ASSERT

Page 26: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller let dataSource = RecipientsTableViewDataSource() let controller = RecipientsViewController(dataSource: dataSource) let _ = controller.view

// Act: Perform the action that triggers the change we want to test dataSource.recipients.append(Recipient(name: "Galois"))

// Assert: Confirm the action had the intended effects XCTAssertEqual(controller.tableView.numberOfRowsInSection(0), 2, "Expected view controller's table view to contain two cells")

let cellIndexPath = NSIndexPath(forRow: 0, inSection: 0) let cell = controller.tableView.cellForRowAtIndexPath(cellIndexPath) XCTAssertEqual(cell!.textLabel!.text!, "GALOIS", "Expected cell for newly added person would be first in the table") }

Page 27: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller let dataSource = RecipientsTableViewDataSource() let controller = RecipientsViewController(dataSource: dataSource) let _ = controller.view

// Act: Perform the action that triggers the change we want to test dataSource.recipients.append(Recipient(name: "Galois"))

// Assert: Confirm the action had the intended effects XCTAssertEqual(controller.tableView.numberOfRowsInSection(0), 2, "Expected view controller's table view to contain two cells")

let cellIndexPath = NSIndexPath(forRow: 0, inSection: 0) let cell = controller.tableView.cellForRowAtIndexPath(cellIndexPath) XCTAssertEqual(cell!.textLabel!.text!, "GALOIS", "Expected cell for newly added person would be first in the table") }

Page 28: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller let dataSource = RecipientsTableViewDataSource() let controller = RecipientsViewController(dataSource: dataSource) let _ = controller.view

// Act: Perform the action that triggers the change we want to test dataSource.recipients.append(Recipient(name: "Galois"))

// Assert: Confirm the action had the intended effects XCTAssertEqual(controller.tableView.numberOfRowsInSection(0), 2, "Expected view controller's table view to contain two cells")

let cellIndexPath = NSIndexPath(forRow: 0, inSection: 0) let cell = controller.tableView.cellForRowAtIndexPath(cellIndexPath) XCTAssertEqual(cell!.textLabel!.text!, "GALOIS", "Expected cell for newly added person would be first in the table") }

Page 29: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller let dataSource = RecipientsTableViewDataSource() let controller = RecipientsViewController(dataSource: dataSource) let _ = controller.view

// Act: Perform the action that triggers the change we want to test dataSource.recipients.append(Recipient(name: "Galois"))

// Assert: Confirm the action had the intended effects XCTAssertEqual(controller.tableView.numberOfRowsInSection(0), 2, "Expected view controller's table view to contain two cells")

let cellIndexPath = NSIndexPath(forRow: 0, inSection: 0) let cell = controller.tableView.cellForRowAtIndexPath(cellIndexPath) XCTAssertEqual(cell!.textLabel!.text!, "GALOIS", "Expected cell for newly added person would be first in the table") }

Page 30: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller let dataSource = RecipientsTableViewDataSource() let controller = RecipientsViewController(dataSource: dataSource) let _ = controller.view

// Act: Perform the action that triggers the change we want to test dataSource.recipients.append(Recipient(name: "Galois"))

// Assert: Confirm the action had the intended effects XCTAssertEqual(controller.tableView.numberOfRowsInSection(0), 2, "Expected view controller's table view to contain two cells")

let cellIndexPath = NSIndexPath(forRow: 0, inSection: 0) let cell = controller.tableView.cellForRowAtIndexPath(cellIndexPath) XCTAssertEqual(cell!.textLabel!.text!, "GALOIS", "Expected cell for newly added person would be first in the table") }

Page 31: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller let dataSource = RecipientsTableViewDataSource() let controller = RecipientsViewController(dataSource: dataSource) let _ = controller.view

// Act: Perform the action that triggers the change we want to test dataSource.recipients.append(Recipient(name: "Galois"))

// Assert: Confirm the action had the intended effects XCTAssertEqual(controller.tableView.numberOfRowsInSection(0), 2, "Expected view controller's table view to contain two cells")

let cellIndexPath = NSIndexPath(forRow: 0, inSection: 0) let cell = controller.tableView.cellForRowAtIndexPath(cellIndexPath) XCTAssertEqual(cell!.textLabel!.text!, "GALOIS", "Expected cell for newly added person would be first in the table") }

Page 32: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 33: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 34: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 35: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 36: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 37: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 38: Quick: Better Tests via Incremental Setup

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Arrange: Prepare the view controller // Act: None in this case XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(cell!.textLabel!.text!, "+") }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(cell!.textLabel!.text!, "GALOIS") }

func testTableViewAfterAddingPersonStillContainsAddCell() { // Arrange: Prepare the view controller // Act: Add a person XCTAssertEqual(viewController.tableView.numberOfRowsInSection(0), 1) XCTAssertEqual(lastCell!.textLabel!.text!, "+") }

Page 39: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 40: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 41: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 42: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 43: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 44: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 45: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 46: Quick: Better Tests via Incremental Setup

class RecipientsViewControllerTests: XCTestCase { var dataSource: RecipientsTableViewDataSource! var viewController: RecipientsViewController!

override func setUp() { // Arrange: Prepare the view controller dataSource = RecipientsTableViewDataSource() viewController = RecipientsViewController(dataSource: dataSource) }

func testTableViewBeforeAddingAnyCellsContainsAddCell() { // Act: None in this case // Assert: One cell in table }

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" } }

Page 47: Quick: Better Tests via Incremental Setup
Page 48: Quick: Better Tests via Incremental Setup
Page 49: Quick: Better Tests via Incremental Setup

incremental arrange

Page 50: Quick: Better Tests via Incremental Setup
Page 51: Quick: Better Tests via Incremental Setup
Page 52: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" }

func testTableViewWhenFullDoesNotContainAddCell() { // Arrange: Add 5 people to table // Act: None in this case // Assert: Last cell in table view is not "+" }

func testTableViewWhenFullDoesNotAddPeople() { // Arrange: Add 5 people to table // Act: Add another person // Assert: Still only 5 people in table }

Page 53: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" }

func testTableViewWhenFullDoesNotContainAddCell() { // Arrange: Add 5 people to table // Act: None in this case // Assert: Last cell in table view is not "+" }

func testTableViewWhenFullDoesNotAddPeople() { // Arrange: Add 5 people to table // Act: Add another person // Assert: Still only 5 people in table }

Page 54: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" }

func testTableViewWhenFullDoesNotContainAddCell() { // Arrange: Add 5 people to table // Act: None in this case // Assert: Last cell in table view is not "+" }

func testTableViewWhenFullDoesNotAddPeople() { // Arrange: Add 5 people to table // Act: Add another person // Assert: Still only 5 people in table }

Page 55: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" }

func testTableViewWhenFullDoesNotContainAddCell() { // Arrange: Add 5 people to table // Act: None in this case // Assert: Last cell in table view is not "+" }

func testTableViewWhenFullDoesNotAddPeople() { // Arrange: Add 5 people to table // Act: Add another person // Assert: Still only 5 people in table }

Page 56: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" }

func testTableViewWhenFullDoesNotContainAddCell() { // Arrange: Add 5 people to table // Act: None in this case // Assert: Last cell in table view is not "+" }

func testTableViewWhenFullDoesNotAddPeople() { // Arrange: Add 5 people to table // Act: Add another person // Assert: Still only 5 people in table }

Page 57: Quick: Better Tests via Incremental Setup

func testTableViewAfterAddingPersonContainsACellForThatPerson() { // Act: Add a person // Assert: First cell in table is "GALOIS" }

func testTableViewWhenFullDoesNotContainAddCell() { // Arrange: Add 5 people to table // Act: None in this case // Assert: Last cell in table view is not "+" }

func testTableViewWhenFullDoesNotAddPeople() { // Arrange: Add 5 people to table // Act: Add another person // Assert: Still only 5 people in table }

Page 58: Quick: Better Tests via Incremental Setup

var controller: RecipientsViewController! var dataSource: RecipientsTableViewDataSource! var fullController: RecipientsViewController! var fullDataSource: RecipientsTableViewDataSource!

override func setUp() { // Arrange #1: Prepare the empty view controller dataSource = RecipientsTableViewDataSource() controller = RecipientsViewController(dataSource: dataSource)

// Arrange #2: Prepare the full view controller fullDataSource = RecipientsTableViewDataSource() fullDataSource.recipients.extend([ Recipient(name: "Galois"), Recipient(name: "Lagrange"), Recipient(name: "Gauss"), Recipient(name: "Riemann"), Recipient(name: "Poincaré"), ]) fullController = RecipientsViewController(dataSource: fullDataSource) }

Page 59: Quick: Better Tests via Incremental Setup

var controller: RecipientsViewController! var dataSource: RecipientsTableViewDataSource! var fullController: RecipientsViewController! var fullDataSource: RecipientsTableViewDataSource!

override func setUp() { // Arrange #1: Prepare the empty view controller dataSource = RecipientsTableViewDataSource() controller = RecipientsViewController(dataSource: dataSource)

// Arrange #2: Prepare the full view controller fullDataSource = RecipientsTableViewDataSource() fullDataSource.recipients.extend([ Recipient(name: "Galois"), Recipient(name: "Lagrange"), Recipient(name: "Gauss"), Recipient(name: "Riemann"), Recipient(name: "Poincaré"), ]) fullController = RecipientsViewController(dataSource: fullDataSource) }

Page 60: Quick: Better Tests via Incremental Setup

var controller: RecipientsViewController! var dataSource: RecipientsTableViewDataSource! var fullController: RecipientsViewController! var fullDataSource: RecipientsTableViewDataSource!

override func setUp() { // Arrange #1: Prepare the empty view controller dataSource = RecipientsTableViewDataSource() controller = RecipientsViewController(dataSource: dataSource)

// Arrange #2: Prepare the full view controller fullDataSource = RecipientsTableViewDataSource() fullDataSource.recipients.extend([ Recipient(name: "Galois"), Recipient(name: "Lagrange"), Recipient(name: "Gauss"), Recipient(name: "Riemann"), Recipient(name: "Poincaré"), ]) fullController = RecipientsViewController(dataSource: fullDataSource) }

Page 61: Quick: Better Tests via Incremental Setup

var controller: RecipientsViewController! var dataSource: RecipientsTableViewDataSource! var fullController: RecipientsViewController! var fullDataSource: RecipientsTableViewDataSource!

override func setUp() { // Arrange #1: Prepare the empty view controller dataSource = RecipientsTableViewDataSource() controller = RecipientsViewController(dataSource: dataSource)

// Arrange #2: Prepare the full view controller fullDataSource = RecipientsTableViewDataSource() fullDataSource.recipients.extend([ Recipient(name: "Galois"), Recipient(name: "Lagrange"), Recipient(name: "Gauss"), Recipient(name: "Riemann"), Recipient(name: "Poincaré"), ]) fullController = RecipientsViewController(dataSource: fullDataSource) }

Page 62: Quick: Better Tests via Incremental Setup

var controller: RecipientsViewController! var dataSource: RecipientsTableViewDataSource! var fullController: RecipientsViewController! var fullDataSource: RecipientsTableViewDataSource!

override func setUp() { // Arrange #1: Prepare the empty view controller dataSource = RecipientsTableViewDataSource() controller = RecipientsViewController(dataSource: dataSource)

// Arrange #2: Prepare the full view controller fullDataSource = RecipientsTableViewDataSource() fullDataSource.recipients.extend([ Recipient(name: "Galois"), Recipient(name: "Lagrange"), Recipient(name: "Gauss"), Recipient(name: "Riemann"), Recipient(name: "Poincaré"), ]) fullController = RecipientsViewController(dataSource: fullDataSource) }

Page 63: Quick: Better Tests via Incremental Setup

var controller: RecipientsViewController! var dataSource: RecipientsTableViewDataSource! var fullController: RecipientsViewController! var fullDataSource: RecipientsTableViewDataSource!

override func setUp() { // Arrange #1: Prepare the empty view controller dataSource = RecipientsTableViewDataSource() controller = RecipientsViewController(dataSource: dataSource)

// Arrange #2: Prepare the full view controller fullDataSource = RecipientsTableViewDataSource() fullDataSource.recipients.extend([ Recipient(name: "Galois"), Recipient(name: "Lagrange"), Recipient(name: "Gauss"), Recipient(name: "Riemann"), Recipient(name: "Poincaré"), ]) fullController = RecipientsViewController(dataSource: fullDataSource) }

Page 64: Quick: Better Tests via Incremental Setup
Page 65: Quick: Better Tests via Incremental Setup
Page 66: Quick: Better Tests via Incremental Setup
Page 67: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 68: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 69: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 70: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 71: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 72: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 73: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 74: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 75: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 76: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 77: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 78: Quick: Better Tests via Incremental Setup

describe("RecipientsTableViewDataSource") { var dataSource: RecipientsTableViewDataSource! beforeEach { dataSource = RecipientsTableViewDataSource() }

describe("isFull") { context("when it contains 5 or fewer people") { it("returns false") { /* ... */ } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois"), ...]) } it("returns true") { /* ... */ } } } }

Page 79: Quick: Better Tests via Incremental Setup

example = test

Page 80: Quick: Better Tests via Incremental Setup

example group = group of tests

Page 81: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 82: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 83: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 84: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 85: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 86: Quick: Better Tests via Incremental Setup

typealias BeforeEachClosure = () -> ()

class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]()

weak var parent: ExampleGroup? var children = [ExampleGroup]() }

Page 87: Quick: Better Tests via Incremental Setup

typealias BeforeEachClosure = () -> ()

class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]()

weak var parent: ExampleGroup? var children = [ExampleGroup]() }

Page 88: Quick: Better Tests via Incremental Setup

typealias BeforeEachClosure = () -> ()

class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]()

weak var parent: ExampleGroup? var children = [ExampleGroup]() }

Page 89: Quick: Better Tests via Incremental Setup

typealias BeforeEachClosure = () -> ()

class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]()

weak var parent: ExampleGroup? var children = [ExampleGroup]() }

Page 90: Quick: Better Tests via Incremental Setup

typealias BeforeEachClosure = () -> ()

class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]()

weak var parent: ExampleGroup? var children = [ExampleGroup]() }

Page 91: Quick: Better Tests via Incremental Setup

typealias BeforeEachClosure = () -> ()

class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]()

weak var parent: ExampleGroup? var children = [ExampleGroup]() }

Page 92: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 93: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 94: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 95: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 96: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 97: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 98: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 99: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 100: Quick: Better Tests via Incremental Setup

typealias ExampleClosure = () -> ()

class Example { let exampleGroup: ExampleGroup let closure: ExampleClosure

func run() { runBeforeEach(); closure() }

func runBeforeEach() { var beforeEachClosures = [BeforeEachClosure]()

var group: ExampleGroup? = exampleGroup while (group != nil) { beforeEachClosures.extend(group!.beforeEachClosures.reverse()) group = group!.parent }

for closure in beforeEachClosures.reverse() { closure() } } }

Page 101: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 102: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 103: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 104: Quick: Better Tests via Incremental Setup

describe("isFull") { beforeEach { dataSource = RecipientsTableViewDataSource() }

context("when it contains 5 or fewer people") { it("returns false") { XCTAssertFalse(dataSource.isFull) } }

context("when it contains 6 or more people") { beforeEach { dataSource.recipients.extend([Recipient(name: "Galois")]) }

it("returns true") { XCTAssert(dataSource.isFull) } } }

Page 105: Quick: Better Tests via Incremental Setup

incremental arrange is a killer feature

Page 106: Quick: Better Tests via Incremental Setup

✓ incremental teardown

Page 107: Quick: Better Tests via Incremental Setup

✓ incremental teardown

afterEach { // ... }

Page 108: Quick: Better Tests via Incremental Setup

✓ incremental teardown✓ suite-wide arrange

beforeSuite { // ... }

Page 109: Quick: Better Tests via Incremental Setup

✓ incremental teardown✓ suite-wide arrange✓ suite-wide teardown

beforeSuite { // ... }

afterSuite { // ... }

Page 110: Quick: Better Tests via Incremental Setup

✓ incremental teardown✓ suite-wide arrange✓ suite-wide teardown✓ shared assertions

sharedExamples("person cell") { it("shows their name") { // ... } }

itBehavesLike("person cell")

Page 111: Quick: Better Tests via Incremental Setup

✓ incremental teardown✓ suite-wide arrange✓ suite-wide teardown✓ shared assertions✓ better asserts with Nimble

expect([1, 2, 3]).to(contain(2))

Page 112: Quick: Better Tests via Incremental Setup

✓ incremental teardown✓ suite-wide arrange✓ suite-wide teardown✓ shared assertions✓ better asserts with Nimble✓ custom asserts

expect(view).to( haveValidSnapshot())

Page 113: Quick: Better Tests via Incremental Setup

✓ incremental teardown✓ suite-wide arrange✓ suite-wide teardown✓ shared assertions✓ better asserts with Nimble✓ custom asserts✓ configurable

Page 114: Quick: Better Tests via Incremental Setup

github.com/Quick/Quick

Page 115: Quick: Better Tests via Incremental Setup
Page 116: Quick: Better Tests via Incremental Setup

Ciara Brocklebank <[email protected]>

[Flatiron] FBNY Happy Hour