SlideShare a Scribd company logo
TDD by Controlling
Dependencies
Jorge D. Ortiz-Fuentes
TDD by Controlling Dependencies
You Go First
TDD by Controlling Dependencies
TDD by Controlling
Dependencies
Jorge D. Ortiz-Fuentes
@jdortiz
#Swift2TDD
A Canonical
Examples
production
#Swift2TDD
#Swift2TDD
Agenda
★ TDD
★ Real Life
★ Swift
TDD
TDD
#Swift2TDD
Progress as a developer
★ It does things!
★ It does the things I want!
★ I can prove that it does what I say!
★ I am going to make it do exactly what i say!
Nerdvana
#Swift2TDD
The Rules of Testing
★ We only test our code
★ Only a level of abstraction
★ Only public methods
★ Only one assertion per test
★ Tests are independent of sequence or state
The TDD Dance
Red
Green
Refactor
#Swift2TDD
Pros
★ 100% coverage
★ Detect edge cases
and unforeseen
scenarios
★ Measurable progress
★ Easier to introduce
changes
★ Less debug
★ Decoupled code
★ Explicit
dependencies
★ Single responsibility
★ Autopilot
programming
★ Simpler design
Easier
TDD Cons?
#Swift2TDD
Cons
★ Put the horse before the cart
★ Takes longer
★ Initial investment. Slower and more work in QA
★ Design without the big picture
★ Tests must also be rewritten when requirements
change
★ Other tests are needed too
★ Tests are as bad as code
– Winston Churchill
“Success is stumbling from failure to failure
with no loss of enthusiasm.”
Real
Life
UI Testing
Persistence
Traits
TDD
Swift
+
2
Test the UI
#Swift2TDD
UI Testing
★ Xcode UI Testing ≠ Unit Testing
★ Nor is Kif, Calabash, or Cucumber
(Integration)
★ Unit test is about isolation
View
View Presenter Interactor EntityGateway
Make the view dumb
class SpeakerTableViewCell: UITableViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var dateLabel: UILabel!
}
extension SpeakerTableViewCell: SpeakerCellProtocol {
func displayName(name: String) {
nameLabel.text = name
}
func displayTitle(title: String) {
titleLabel.text = title
}
func displayDateSubmitted(date: String){
dateLabel.text = date
}
}
Testing a label
func testDisplayDateChangesLabelTextToAltValue() {
let labelMock = LabelMock()
sut.dateLabel = labelMock
sut.displayDateSubmitted(speakerAltDateSubmitted)
XCTAssertTrue(labelMock.setTextWasInvoked,
"displayDate must set the text of the label.")
XCTAssertEqual(labelMock.text, speakerAltDateSubmitted,
"displayDate must set the text of the label to the provided text.")
}
// MARK: - Stubs & Mocks
class LabelMock: UILabel {
// MARK: - Properties
var setTextWasInvoked = false
override var text: String? {
didSet {
setTextWasInvoked = true
}
}
}
Test despite the
persistence
#Swift2TDD
Testing Business Logic
★ Persistence seems to be a requirement for
testing the logic
★ But it can be abstracted
★ And the data from the entity gateway
Clean Architecture
View (VC) Presenter
Connector
Interactor Repository
Persistence
WSC
Isolate the user story
class ShowAllSpeakersInteractor {
// MARK: - Properties
let entityGateway: EntityGatewayProtocol
weak var presenter: SpeakersListPresenterProtocol?
// MARK: - Initializers
init(entityGateway: EntityGatewayProtocol) {
self.entityGateway = entityGateway
}
}
extension ShowAllSpeakersInteractor: ShowAllSpeakersInteractorProtocol {
func showAllSpeakers() {
let entities = entityGateway.fetchAllSpeakers()
let displayData = entities.map({entity in
return SpeakerDisplayData(speaker: entity)})
presenter?.presentAllSpeakers(displayData)
}
}
Testing a use case
func testEntityIstransformedIntoDisplayData() {
entityGateway.entities = [Speaker(name: speakerMainName,
title: speakerMainTitle,
synopsis: speakerMainSynopsis,
dateSubmitted: speakerMainDateSubmitted)]
sut.showAllSpeakers()
guard presenter.displayData.count == entityGateway.entities.count
else { XCTFail(“There must be one and only one display data per each
entity of the repo.”)
return }
let speakerData = presenter.displayData[0]
XCTAssertEqual(speakerData.name, speakerMainName,
"Speaker name must be copied onto the display data.")
XCTAssertEqual(speakerData.title, speakerMainTitle,
"Speaker title must be copied onto the display data.")
XCTAssertEqual(speakerData.dateSubmitted, speakerMainDateSubmitted,
"Speaker submitedDate must be copied onto the display data.")
}
Traits
Protocol extensions
protocol SegueHandlerTypeProtocol {
typealias SegueIdentifier: RawRepresentable
}
extension SegueHandlerTypeProtocol where
Self: UIViewController,
SegueIdentifier.RawValue == String {
func performSegueWithIdentifier(segueIdentifier: SegueIdentifier, sender:
AnyObject?) {
performSegueWithIdentifier(segueIdentifier.rawValue, sender: sender)
}
func segueIdentifierForSegue(segue: UIStoryboardSegue) -> SegueIdentifier {
guard let identifier = segue.identifier,
segueIdentifier = SegueIdentifier(rawValue: identifier)
else { fatalError("Invalid segue identifier (segue.identifier).") }
return segueIdentifier
}
}
As explained in WWDC 2015 Swift in Practice
Testing a Trait
var sut: SegueHandlerTypeViewControlerMock!
class SegueHandlerTypeViewControlerMock: UIViewController,
SegueHandlerTypeProtocol {
// MARK: - Properties
var identifierToPerformSegue: String?
var senderPerformingSegue: AnyObject?
enum SegueIdentifier: String {
case FirstSegue = "FirstSegueString"
case SecondSegue = "SecondSegueString"
}
// MARK: - Mocks & Stubs
override func performSegueWithIdentifier(identifier: String, sender:
AnyObject?) {
identifierToPerformSegue = identifier
senderPerformingSegue = sender
}
}
Testing a trait (2)
func testPerformSegueWithIdentifierInvokesClassicVersion() {
sut.performSegueWithIdentifier(SegueHandlerTypeViewControlerMock.SegueIdentifier.FirstSeg
ue, sender: nil)
XCTAssertNotNil(sut.identifierToPerformSegue,
"Classic version of performSegueWithIdentifier must be invoked by the one in
the protocol extension.")
}
func testPerformSegueWithIdentifierPassesRawValueOfFirstIdentifier() {
sut.performSegueWithIdentifier(SegueHandlerTypeViewControlerMock.SegueIdentifier.FirstSeg
ue, sender: nil)
XCTAssertEqual(sut.identifierToPerformSegue, firstSegueString,
"Identifier must correspond to the raw value of the enum case.")
}
func testPerformSegueWithIdentifierPassesRawValueOfSecondIdentifier() {
sut.performSegueWithIdentifier(SegueHandlerTypeViewControlerMock.SegueIdentifier.SecondSe
gue, sender: nil)
XCTAssertEqual(sut.identifierToPerformSegue, secondSegueString,
"Identifier must correspond to the raw value of the enum case.")
}
– Thomas A. Edison
“I have not failed. I’ve just found 10,000
ways that won’t work.”
Thank
you!
@jdortiz
#Swift2TDD
TDD by Controlling Dependencies

More Related Content

PDF
All things that are not code
PDF
AST Transformations: Groovy’s best kept secret by Andres Almiray
ODP
Groovy AST Transformations
PDF
G*におけるソフトウェアテスト・シーズンIII
PDF
A Brief Introduction to the Qt Application Framework
PDF
The Ring programming language version 1.6 book - Part 41 of 189
PDF
Java day 2016.pptx
PDF
The Ring programming language version 1.5.3 book - Part 13 of 184
All things that are not code
AST Transformations: Groovy’s best kept secret by Andres Almiray
Groovy AST Transformations
G*におけるソフトウェアテスト・シーズンIII
A Brief Introduction to the Qt Application Framework
The Ring programming language version 1.6 book - Part 41 of 189
Java day 2016.pptx
The Ring programming language version 1.5.3 book - Part 13 of 184

What's hot (20)

PDF
Protocols promised-land-2
PDF
GraphQL API in Clojure
PDF
The Ring programming language version 1.7 book - Part 85 of 196
PDF
The Ring programming language version 1.8 book - Part 17 of 202
PDF
The Ring programming language version 1.10 book - Part 87 of 212
PDF
The Ring programming language version 1.5.4 book - Part 81 of 185
PDF
The Ring programming language version 1.3 book - Part 57 of 88
PDF
OTcl and C++ linkages in NS2
PDF
Typescript is the best
PDF
Typescript is the best by Maxim Kryuk
PDF
The Ring programming language version 1.7 book - Part 79 of 196
PDF
The Ring programming language version 1.5.4 book - Part 82 of 185
PDF
Spockを使おう!
PDF
The Ring programming language version 1.9 book - Part 19 of 210
PDF
The Ring programming language version 1.8 book - Part 88 of 202
PPT
Groovy AST Demystified
PDF
The Ring programming language version 1.7 book - Part 87 of 196
PPTX
Annotation processor and compiler plugin
PDF
The Ring programming language version 1.8 book - Part 14 of 202
PDF
Introduction to typescript
Protocols promised-land-2
GraphQL API in Clojure
The Ring programming language version 1.7 book - Part 85 of 196
The Ring programming language version 1.8 book - Part 17 of 202
The Ring programming language version 1.10 book - Part 87 of 212
The Ring programming language version 1.5.4 book - Part 81 of 185
The Ring programming language version 1.3 book - Part 57 of 88
OTcl and C++ linkages in NS2
Typescript is the best
Typescript is the best by Maxim Kryuk
The Ring programming language version 1.7 book - Part 79 of 196
The Ring programming language version 1.5.4 book - Part 82 of 185
Spockを使おう!
The Ring programming language version 1.9 book - Part 19 of 210
The Ring programming language version 1.8 book - Part 88 of 202
Groovy AST Demystified
The Ring programming language version 1.7 book - Part 87 of 196
Annotation processor and compiler plugin
The Ring programming language version 1.8 book - Part 14 of 202
Introduction to typescript
Ad

Viewers also liked (18)

PDF
Manual do-laboratório
PDF
Vanguard award
PPTX
DOC
Vijay_resume
PPTX
Ideba Q3, 2015 Visual Portfolio
PDF
A la boulangie
PPT
Imformatica
DOCX
PPT
خلاصة تجربة 30 عامًا في دعوة غير المسلمين (ميدانيًا وإلكترونيًا)
PDF
A systematic review_of_internet_banking
PDF
Aula 2-planej e caracteristicas-tet
DOCX
1 fil prov. especifica 4 bimestre
PPTX
Substance Use Disorders
PPTX
выпускница школы № 92
PDF
Brunswick Intelligence - Building reputational resilience to cyber attack
PDF
A.b aula 4 amostragem
PPTX
#FlipMyFunnel Atlanta 2016 - Jason Jue - Personalize The B2B Customer Journey...
PPTX
Musu zodis
Manual do-laboratório
Vanguard award
Vijay_resume
Ideba Q3, 2015 Visual Portfolio
A la boulangie
Imformatica
خلاصة تجربة 30 عامًا في دعوة غير المسلمين (ميدانيًا وإلكترونيًا)
A systematic review_of_internet_banking
Aula 2-planej e caracteristicas-tet
1 fil prov. especifica 4 bimestre
Substance Use Disorders
выпускница школы № 92
Brunswick Intelligence - Building reputational resilience to cyber attack
A.b aula 4 amostragem
#FlipMyFunnel Atlanta 2016 - Jason Jue - Personalize The B2B Customer Journey...
Musu zodis
Ad

Similar to TDD by Controlling Dependencies (20)

PDF
TDD and mobile development: some forgotten techniques, illustrated with Android
PDF
Clean coding-practices
PDF
지금 당장 (유사) BDD 시작하기
KEY
Gwt and Xtend
PDF
Why the Dark Side should use Swift and a SOLID Architecture
PDF
Matteo Vaccari - TDD per Android | Codemotion Milan 2015
PDF
Architecting Alive Apps
PDF
Refactoring In Tdd The Missing Part
PDF
Android and the Seven Dwarfs from Devox'15
PDF
Drinking from the Elixir Fountain of Resilience
PDF
Introduction to Griffon
PPTX
Tdd & clean code
PDF
Cleaning your architecture with android architecture components
PPTX
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
ODP
Qt Workshop
PDF
Reactive clean architecture
PPTX
2. Design patterns. part #2
PDF
From Legacy to Hexagonal (An Unexpected Android Journey)
PPTX
Q Con Performance Testing At The Edge
PDF
Home Improvement: Architecture & Kotlin
TDD and mobile development: some forgotten techniques, illustrated with Android
Clean coding-practices
지금 당장 (유사) BDD 시작하기
Gwt and Xtend
Why the Dark Side should use Swift and a SOLID Architecture
Matteo Vaccari - TDD per Android | Codemotion Milan 2015
Architecting Alive Apps
Refactoring In Tdd The Missing Part
Android and the Seven Dwarfs from Devox'15
Drinking from the Elixir Fountain of Resilience
Introduction to Griffon
Tdd & clean code
Cleaning your architecture with android architecture components
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
Qt Workshop
Reactive clean architecture
2. Design patterns. part #2
From Legacy to Hexagonal (An Unexpected Android Journey)
Q Con Performance Testing At The Edge
Home Improvement: Architecture & Kotlin

More from Jorge Ortiz (20)

PDF
Tell Me Quando - Implementing Feature Flags
PDF
Unit Test your Views
PDF
Control your Voice like a Bene Gesserit
PDF
Kata gilded rose en Golang
PDF
CYA: Cover Your App
PDF
Refactor your way forward
PDF
201710 Fly Me to the View - iOS Conf SG
PDF
Architectural superpowers
PDF
iOS advanced architecture workshop 3h edition
PDF
Android clean architecture workshop 3h edition
PDF
To Protect & To Serve
PDF
Clean architecture workshop
PDF
Escape from Mars
PDF
Dependence day insurgence
PDF
Architectural superpowers
PDF
TDD for the masses
PDF
7 Stages of Unit Testing in iOS
PDF
Building for perfection
PDF
Unit testing in swift 2 - The before & after story
PDF
Core Data in Modern Times
Tell Me Quando - Implementing Feature Flags
Unit Test your Views
Control your Voice like a Bene Gesserit
Kata gilded rose en Golang
CYA: Cover Your App
Refactor your way forward
201710 Fly Me to the View - iOS Conf SG
Architectural superpowers
iOS advanced architecture workshop 3h edition
Android clean architecture workshop 3h edition
To Protect & To Serve
Clean architecture workshop
Escape from Mars
Dependence day insurgence
Architectural superpowers
TDD for the masses
7 Stages of Unit Testing in iOS
Building for perfection
Unit testing in swift 2 - The before & after story
Core Data in Modern Times

Recently uploaded (20)

PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Encapsulation theory and applications.pdf
PPT
Teaching material agriculture food technology
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPTX
Programs and apps: productivity, graphics, security and other tools
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
KodekX | Application Modernization Development
PDF
MIND Revenue Release Quarter 2 2025 Press Release
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Electronic commerce courselecture one. Pdf
Encapsulation theory and applications.pdf
Teaching material agriculture food technology
Understanding_Digital_Forensics_Presentation.pptx
20250228 LYD VKU AI Blended-Learning.pptx
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Spectral efficient network and resource selection model in 5G networks
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Chapter 3 Spatial Domain Image Processing.pdf
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Programs and apps: productivity, graphics, security and other tools
MYSQL Presentation for SQL database connectivity
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?
Dropbox Q2 2025 Financial Results & Investor Presentation
KodekX | Application Modernization Development
MIND Revenue Release Quarter 2 2025 Press Release

TDD by Controlling Dependencies

  • 5. TDD by Controlling Dependencies Jorge D. Ortiz-Fuentes @jdortiz #Swift2TDD
  • 8. TDD
  • 9. TDD
  • 10. #Swift2TDD Progress as a developer ★ It does things! ★ It does the things I want! ★ I can prove that it does what I say! ★ I am going to make it do exactly what i say! Nerdvana
  • 11. #Swift2TDD The Rules of Testing ★ We only test our code ★ Only a level of abstraction ★ Only public methods ★ Only one assertion per test ★ Tests are independent of sequence or state
  • 14. #Swift2TDD Pros ★ 100% coverage ★ Detect edge cases and unforeseen scenarios ★ Measurable progress ★ Easier to introduce changes ★ Less debug ★ Decoupled code ★ Explicit dependencies ★ Single responsibility ★ Autopilot programming ★ Simpler design Easier
  • 16. #Swift2TDD Cons ★ Put the horse before the cart ★ Takes longer ★ Initial investment. Slower and more work in QA ★ Design without the big picture ★ Tests must also be rewritten when requirements change ★ Other tests are needed too ★ Tests are as bad as code
  • 17. – Winston Churchill “Success is stumbling from failure to failure with no loss of enthusiasm.”
  • 24. #Swift2TDD UI Testing ★ Xcode UI Testing ≠ Unit Testing ★ Nor is Kif, Calabash, or Cucumber (Integration) ★ Unit test is about isolation
  • 26. Make the view dumb class SpeakerTableViewCell: UITableViewCell { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var dateLabel: UILabel! } extension SpeakerTableViewCell: SpeakerCellProtocol { func displayName(name: String) { nameLabel.text = name } func displayTitle(title: String) { titleLabel.text = title } func displayDateSubmitted(date: String){ dateLabel.text = date } }
  • 27. Testing a label func testDisplayDateChangesLabelTextToAltValue() { let labelMock = LabelMock() sut.dateLabel = labelMock sut.displayDateSubmitted(speakerAltDateSubmitted) XCTAssertTrue(labelMock.setTextWasInvoked, "displayDate must set the text of the label.") XCTAssertEqual(labelMock.text, speakerAltDateSubmitted, "displayDate must set the text of the label to the provided text.") } // MARK: - Stubs & Mocks class LabelMock: UILabel { // MARK: - Properties var setTextWasInvoked = false override var text: String? { didSet { setTextWasInvoked = true } } }
  • 29. #Swift2TDD Testing Business Logic ★ Persistence seems to be a requirement for testing the logic ★ But it can be abstracted ★ And the data from the entity gateway
  • 30. Clean Architecture View (VC) Presenter Connector Interactor Repository Persistence WSC
  • 31. Isolate the user story class ShowAllSpeakersInteractor { // MARK: - Properties let entityGateway: EntityGatewayProtocol weak var presenter: SpeakersListPresenterProtocol? // MARK: - Initializers init(entityGateway: EntityGatewayProtocol) { self.entityGateway = entityGateway } } extension ShowAllSpeakersInteractor: ShowAllSpeakersInteractorProtocol { func showAllSpeakers() { let entities = entityGateway.fetchAllSpeakers() let displayData = entities.map({entity in return SpeakerDisplayData(speaker: entity)}) presenter?.presentAllSpeakers(displayData) } }
  • 32. Testing a use case func testEntityIstransformedIntoDisplayData() { entityGateway.entities = [Speaker(name: speakerMainName, title: speakerMainTitle, synopsis: speakerMainSynopsis, dateSubmitted: speakerMainDateSubmitted)] sut.showAllSpeakers() guard presenter.displayData.count == entityGateway.entities.count else { XCTFail(“There must be one and only one display data per each entity of the repo.”) return } let speakerData = presenter.displayData[0] XCTAssertEqual(speakerData.name, speakerMainName, "Speaker name must be copied onto the display data.") XCTAssertEqual(speakerData.title, speakerMainTitle, "Speaker title must be copied onto the display data.") XCTAssertEqual(speakerData.dateSubmitted, speakerMainDateSubmitted, "Speaker submitedDate must be copied onto the display data.") }
  • 34. Protocol extensions protocol SegueHandlerTypeProtocol { typealias SegueIdentifier: RawRepresentable } extension SegueHandlerTypeProtocol where Self: UIViewController, SegueIdentifier.RawValue == String { func performSegueWithIdentifier(segueIdentifier: SegueIdentifier, sender: AnyObject?) { performSegueWithIdentifier(segueIdentifier.rawValue, sender: sender) } func segueIdentifierForSegue(segue: UIStoryboardSegue) -> SegueIdentifier { guard let identifier = segue.identifier, segueIdentifier = SegueIdentifier(rawValue: identifier) else { fatalError("Invalid segue identifier (segue.identifier).") } return segueIdentifier } } As explained in WWDC 2015 Swift in Practice
  • 35. Testing a Trait var sut: SegueHandlerTypeViewControlerMock! class SegueHandlerTypeViewControlerMock: UIViewController, SegueHandlerTypeProtocol { // MARK: - Properties var identifierToPerformSegue: String? var senderPerformingSegue: AnyObject? enum SegueIdentifier: String { case FirstSegue = "FirstSegueString" case SecondSegue = "SecondSegueString" } // MARK: - Mocks & Stubs override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) { identifierToPerformSegue = identifier senderPerformingSegue = sender } }
  • 36. Testing a trait (2) func testPerformSegueWithIdentifierInvokesClassicVersion() { sut.performSegueWithIdentifier(SegueHandlerTypeViewControlerMock.SegueIdentifier.FirstSeg ue, sender: nil) XCTAssertNotNil(sut.identifierToPerformSegue, "Classic version of performSegueWithIdentifier must be invoked by the one in the protocol extension.") } func testPerformSegueWithIdentifierPassesRawValueOfFirstIdentifier() { sut.performSegueWithIdentifier(SegueHandlerTypeViewControlerMock.SegueIdentifier.FirstSeg ue, sender: nil) XCTAssertEqual(sut.identifierToPerformSegue, firstSegueString, "Identifier must correspond to the raw value of the enum case.") } func testPerformSegueWithIdentifierPassesRawValueOfSecondIdentifier() { sut.performSegueWithIdentifier(SegueHandlerTypeViewControlerMock.SegueIdentifier.SecondSe gue, sender: nil) XCTAssertEqual(sut.identifierToPerformSegue, secondSegueString, "Identifier must correspond to the raw value of the enum case.") }
  • 37. – Thomas A. Edison “I have not failed. I’ve just found 10,000 ways that won’t work.”