Quick: Better Tests via Incremental Setup

116

Transcript of Quick: Better Tests via Incremental Setup

testing?

does your app do what you think it does?

how?

run the app

println()

not that simple

big app?

working with others?

works?

manual testing doesn’t scale

manual testing is vague

automated tests are fast

automated tests are precise

testing apps is awesome

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

some tests are more awesome than others

good tests are clear

ARRANGE ACT

ASSERT

ARRANGE ACT

ASSERT

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") }

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") }

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") }

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") }

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") }

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") }

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!, "+") }

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!, "+") }

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!, "+") }

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!, "+") }

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!, "+") }

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!, "+") }

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!, "+") }

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" } }

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" } }

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" } }

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" } }

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" } }

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" } }

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" } }

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" } }

incremental arrange

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 }

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 }

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 }

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 }

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 }

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 }

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) }

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) }

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) }

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) }

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) }

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) }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

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") { /* ... */ } } } }

example = test

example group = group of tests

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) } } }

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) } } }

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) } } }

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) } } }

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) } } }

typealias BeforeEachClosure = () -> ()

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

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

typealias BeforeEachClosure = () -> ()

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

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

typealias BeforeEachClosure = () -> ()

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

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

typealias BeforeEachClosure = () -> ()

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

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

typealias BeforeEachClosure = () -> ()

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

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

typealias BeforeEachClosure = () -> ()

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

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

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() } } }

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() } } }

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() } } }

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() } } }

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() } } }

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() } } }

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() } } }

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() } } }

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() } } }

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) } } }

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) } } }

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) } } }

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) } } }

incremental arrange is a killer feature

✓ incremental teardown

✓ incremental teardown

afterEach { // ... }

✓ incremental teardown✓ suite-wide arrange

beforeSuite { // ... }

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

beforeSuite { // ... }

afterSuite { // ... }

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

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

itBehavesLike("person cell")

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

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

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

expect(view).to( haveValidSnapshot())

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

github.com/Quick/Quick

Ciara Brocklebank <[email protected]>

[Flatiron] FBNY Happy Hour