SlideShare a Scribd company logo
Quick: Better Tests via Incremental Setup
Quick: Better Tests via Incremental Setup
testing?
doesyourappdo
whatyouthink
itdoes?
how?
runtheapp
Quick: Better Tests via Incremental Setup
Quick: Better Tests via Incremental Setup
println()
notthat
simple
bigapp?
workingwith
others?
works?
manualtesting
doesn’tscale
manualtesting
isvague
automated
testsarefast
automated
testsareprecise
Quick: Better Tests via Incremental Setup
Quick: Better Tests via Incremental Setup
testingapps
isawesome
testingappsiscoolwhen
you’repartofateam
sometestsaremore
awesomethanothers
goodtests
areclear
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"
}
}
Quick: Better Tests via Incremental Setup
Quick: Better Tests via Incremental Setup
incremental
arrange
Quick: Better Tests via Incremental Setup
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
}
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)
}
Quick: Better Tests via Incremental Setup
Quick: Better Tests via Incremental Setup
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") { /* ... */ }
}
}
}
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
examplegroup
=groupoftests
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)
}
}
}
incrementalarrangeisa
killerfeature
✓ 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
Quick: Better Tests via Incremental Setup
CiaraBrocklebank
<ciara.brocklebank@fb.com>
[Flatiron]FBNYHappyHour

More Related Content

What's hot (18)

PDF
Swift Delhi: Practical POP
Natasha Murashev
 
PDF
Deep Dive into React Hooks
Felix Kühl
 
PDF
New improvements for web developers - frontend.fi, Helsinki
Robert Nyman
 
PPTX
Owl: The New Odoo UI Framework
Odoo
 
PDF
Adventures In JavaScript Testing
Thomas Fuchs
 
PDF
Understanding JavaScript Testing
jeresig
 
PDF
04 Advanced Javascript
crgwbr
 
PDF
UI 모듈화로 워라밸 지키기
NAVER SHOPPING
 
PDF
Simplified Android Development with Simple-Stack
Gabor Varadi
 
PDF
Protocol-Oriented MVVM (extended edition)
Natasha Murashev
 
PPTX
Adding a modern twist to legacy web applications
Jeff Durta
 
PDF
Reliable Javascript
Glenn Stovall
 
PDF
Testing Ember Apps: Managing Dependency
Matthew Beale
 
PDF
Reduxing like a pro
Boris Dinkevich
 
PDF
React lecture
Christoffer Noring
 
PDF
State management in android applications
Gabor Varadi
 
PDF
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Iakiv Kramarenko
 
PDF
Swift Montevideo Meetup - iPhone, una herramienta medica
Washington Miranda
 
Swift Delhi: Practical POP
Natasha Murashev
 
Deep Dive into React Hooks
Felix Kühl
 
New improvements for web developers - frontend.fi, Helsinki
Robert Nyman
 
Owl: The New Odoo UI Framework
Odoo
 
Adventures In JavaScript Testing
Thomas Fuchs
 
Understanding JavaScript Testing
jeresig
 
04 Advanced Javascript
crgwbr
 
UI 모듈화로 워라밸 지키기
NAVER SHOPPING
 
Simplified Android Development with Simple-Stack
Gabor Varadi
 
Protocol-Oriented MVVM (extended edition)
Natasha Murashev
 
Adding a modern twist to legacy web applications
Jeff Durta
 
Reliable Javascript
Glenn Stovall
 
Testing Ember Apps: Managing Dependency
Matthew Beale
 
Reduxing like a pro
Boris Dinkevich
 
React lecture
Christoffer Noring
 
State management in android applications
Gabor Varadi
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Iakiv Kramarenko
 
Swift Montevideo Meetup - iPhone, una herramienta medica
Washington Miranda
 

Similar to Quick: Better Tests via Incremental Setup (8)

PDF
Cocoa heads testing and viewcontrollers
Stijn Willems
 
PDF
Annihilate test smells by refactoring to patterns
cenny2
 
PDF
TDD by Controlling Dependencies
Jorge Ortiz
 
PDF
Snapshot Testing @ CocoaheadsNL
Lars Lockefeer
 
PDF
Unit testing UIView
Pierre Felgines
 
PPTX
TDD & VIPER
Lyle Resnick
 
PDF
Taking the boilerplate out of your tests with Sourcery
Vincent Pradeilles
 
PDF
Swift 함수 커링 사용하기
진성 오
 
Cocoa heads testing and viewcontrollers
Stijn Willems
 
Annihilate test smells by refactoring to patterns
cenny2
 
TDD by Controlling Dependencies
Jorge Ortiz
 
Snapshot Testing @ CocoaheadsNL
Lars Lockefeer
 
Unit testing UIView
Pierre Felgines
 
TDD & VIPER
Lyle Resnick
 
Taking the boilerplate out of your tests with Sourcery
Vincent Pradeilles
 
Swift 함수 커링 사용하기
진성 오
 
Ad

More from Brian Gesiak (10)

PDF
iOS API Design
Brian Gesiak
 
PDF
Property-Based Testing in Objective-C & Swift with Fox
Brian Gesiak
 
PDF
Intel® Xeon® Phi Coprocessor High Performance Programming
Brian Gesiak
 
PDF
iOS UI Component API Design
Brian Gesiak
 
PDF
iOS UI Component API Design
Brian Gesiak
 
PDF
Apple Templates Considered Harmful
Brian Gesiak
 
PDF
アップルのテンプレートは有害と考えられる
Brian Gesiak
 
PDF
RSpec 3.0: Under the Covers
Brian Gesiak
 
PDF
iOS Behavior-Driven Development
Brian Gesiak
 
PDF
iOSビヘイビア駆動開発
Brian Gesiak
 
iOS API Design
Brian Gesiak
 
Property-Based Testing in Objective-C & Swift with Fox
Brian Gesiak
 
Intel® Xeon® Phi Coprocessor High Performance Programming
Brian Gesiak
 
iOS UI Component API Design
Brian Gesiak
 
iOS UI Component API Design
Brian Gesiak
 
Apple Templates Considered Harmful
Brian Gesiak
 
アップルのテンプレートは有害と考えられる
Brian Gesiak
 
RSpec 3.0: Under the Covers
Brian Gesiak
 
iOS Behavior-Driven Development
Brian Gesiak
 
iOSビヘイビア駆動開発
Brian Gesiak
 
Ad

Recently uploaded (20)

PPTX
Smarter Governance with AI: What Every Board Needs to Know
OnBoard
 
PPTX
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
PPTX
MARTSIA: A Tool for Confidential Data Exchange via Public Blockchain - Pitch ...
Michele Kryston
 
PDF
ArcGIS Utility Network Migration - The Hunter Water Story
Safe Software
 
PDF
Optimizing the trajectory of a wheel loader working in short loading cycles
Reno Filla
 
PPTX
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
pcprocore
 
PDF
Unlocking FME Flow’s Potential: Architecture Design for Modern Enterprises
Safe Software
 
PDF
Redefining Work in the Age of AI - What to expect? How to prepare? Why it mat...
Malinda Kapuruge
 
PDF
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
PDF
“MPU+: A Transformative Solution for Next-Gen AI at the Edge,” a Presentation...
Edge AI and Vision Alliance
 
PDF
The Future of Product Management in AI ERA.pdf
Alyona Owens
 
PDF
Java 25 and Beyond - A Roadmap of Innovations
Ana-Maria Mihalceanu
 
PDF
Kubernetes - Architecture & Components.pdf
geethak285
 
PPTX
Practical Applications of AI in Local Government
OnBoard
 
PPTX
Simplifica la seguridad en la nube y la detección de amenazas con FortiCNAPP
Cristian Garcia G.
 
PDF
The Growing Value and Application of FME & GenAI
Safe Software
 
PDF
Darley - FIRST Copenhagen Lightning Talk (2025-06-26) Epochalypse 2038 - Time...
treyka
 
PDF
FME as an Orchestration Tool with Principles From Data Gravity
Safe Software
 
PDF
2025_06_18 - OpenMetadata Community Meeting.pdf
OpenMetadata
 
PDF
Salesforce Summer '25 Release Frenchgathering.pptx.pdf
yosra Saidani
 
Smarter Governance with AI: What Every Board Needs to Know
OnBoard
 
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
MARTSIA: A Tool for Confidential Data Exchange via Public Blockchain - Pitch ...
Michele Kryston
 
ArcGIS Utility Network Migration - The Hunter Water Story
Safe Software
 
Optimizing the trajectory of a wheel loader working in short loading cycles
Reno Filla
 
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
pcprocore
 
Unlocking FME Flow’s Potential: Architecture Design for Modern Enterprises
Safe Software
 
Redefining Work in the Age of AI - What to expect? How to prepare? Why it mat...
Malinda Kapuruge
 
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
“MPU+: A Transformative Solution for Next-Gen AI at the Edge,” a Presentation...
Edge AI and Vision Alliance
 
The Future of Product Management in AI ERA.pdf
Alyona Owens
 
Java 25 and Beyond - A Roadmap of Innovations
Ana-Maria Mihalceanu
 
Kubernetes - Architecture & Components.pdf
geethak285
 
Practical Applications of AI in Local Government
OnBoard
 
Simplifica la seguridad en la nube y la detección de amenazas con FortiCNAPP
Cristian Garcia G.
 
The Growing Value and Application of FME & GenAI
Safe Software
 
Darley - FIRST Copenhagen Lightning Talk (2025-06-26) Epochalypse 2038 - Time...
treyka
 
FME as an Orchestration Tool with Principles From Data Gravity
Safe Software
 
2025_06_18 - OpenMetadata Community Meeting.pdf
OpenMetadata
 
Salesforce Summer '25 Release Frenchgathering.pptx.pdf
yosra Saidani
 

Quick: Better Tests via Incremental Setup

  • 26. 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") }
  • 27. 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") }
  • 28. 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") }
  • 29. 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") }
  • 30. 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") }
  • 31. 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") }
  • 32. 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!, "+") }
  • 33. 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!, "+") }
  • 34. 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!, "+") }
  • 35. 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!, "+") }
  • 36. 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!, "+") }
  • 37. 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!, "+") }
  • 38. 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!, "+") }
  • 39. 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" } }
  • 40. 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" } }
  • 41. 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" } }
  • 42. 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" } }
  • 43. 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" } }
  • 44. 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" } }
  • 45. 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" } }
  • 46. 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" } }
  • 52. 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 }
  • 53. 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 }
  • 54. 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 }
  • 55. 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 }
  • 56. 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 }
  • 57. 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 }
  • 58. 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) }
  • 59. 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) }
  • 60. 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) }
  • 61. 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) }
  • 62. 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) }
  • 63. 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) }
  • 67. 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") { /* ... */ } } } }
  • 68. 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") { /* ... */ } } } }
  • 69. 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") { /* ... */ } } } }
  • 70. 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") { /* ... */ } } } }
  • 71. 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") { /* ... */ } } } }
  • 72. 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") { /* ... */ } } } }
  • 73. 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") { /* ... */ } } } }
  • 74. 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") { /* ... */ } } } }
  • 75. 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") { /* ... */ } } } }
  • 76. 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") { /* ... */ } } } }
  • 77. 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") { /* ... */ } } } }
  • 78. 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") { /* ... */ } } } }
  • 81. 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) } } }
  • 82. 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) } } }
  • 83. 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) } } }
  • 84. 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) } } }
  • 85. 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) } } }
  • 86. typealias BeforeEachClosure = () -> () class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]() weak var parent: ExampleGroup? var children = [ExampleGroup]() }
  • 87. typealias BeforeEachClosure = () -> () class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]() weak var parent: ExampleGroup? var children = [ExampleGroup]() }
  • 88. typealias BeforeEachClosure = () -> () class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]() weak var parent: ExampleGroup? var children = [ExampleGroup]() }
  • 89. typealias BeforeEachClosure = () -> () class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]() weak var parent: ExampleGroup? var children = [ExampleGroup]() }
  • 90. typealias BeforeEachClosure = () -> () class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]() weak var parent: ExampleGroup? var children = [ExampleGroup]() }
  • 91. typealias BeforeEachClosure = () -> () class ExampleGroup { var beforeEachClosures = [BeforeEachClosure]() var examples = [Example]() weak var parent: ExampleGroup? var children = [ExampleGroup]() }
  • 92. 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() } } }
  • 93. 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() } } }
  • 94. 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() } } }
  • 95. 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() } } }
  • 96. 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() } } }
  • 97. 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() } } }
  • 98. 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() } } }
  • 99. 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() } } }
  • 100. 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() } } }
  • 101. 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) } } }
  • 102. 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) } } }
  • 103. 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) } } }
  • 104. 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) } } }
  • 108. ✓ incremental teardown ✓ suite-wide arrange beforeSuite { // ... }
  • 109. ✓ incremental teardown ✓ suite-wide arrange ✓ suite-wide teardown beforeSuite { // ... } afterSuite { // ... }
  • 110. ✓ incremental teardown ✓ suite-wide arrange ✓ suite-wide teardown ✓ shared assertions sharedExamples("person cell") { it("shows their name") { // ... } } itBehavesLike("person cell")
  • 111. ✓ incremental teardown ✓ suite-wide arrange ✓ suite-wide teardown ✓ shared assertions ✓ better asserts with Nimble expect([1, 2, 3]).to(contain(2))
  • 112. ✓ incremental teardown ✓ suite-wide arrange ✓ suite-wide teardown ✓ shared assertions ✓ better asserts with Nimble ✓ custom asserts expect(view).to( haveValidSnapshot())
  • 113. ✓ incremental teardown ✓ suite-wide arrange ✓ suite-wide teardown ✓ shared assertions ✓ better asserts with Nimble ✓ custom asserts ✓ configurable