KEMBAR78
TDD - Test Driven Development in Swift (iOS) with Cuckoo, Quick and Nimble | PDF
TDD
TEST DRIVEN DEVELOPMENT
Jianbin LIN
DRAFT INTERFACE
WRITE TEST THAT
FAILS
IMPLEMENT AND
PASS THE TEST
REFACTOR
func calculateAreaOfSquare(w: Int, h: Int) -> Double { }
START FROM THE INTERFACE
Given w=2, h=2, Expect area to be 4.
WRITE FIRST TEST
IT FAILS.
COMPILATION ERROR IS TDD ERROR
func calculateAreaOfSquare(w: Int, h: Int) -> Double { }
START IMPLEMENTING
func calculateAreaOfSquare(w: Int, h: Int) -> Double {
return w * h
}
IT PASSED.
REFACTOR
func calculateAreaOfRectangle(w: Int, h: Int) -> Double { }
func calculateAreaOfSquare(w: Int, h: Int) -> Double { }
Given w=-1,h=-1, Expect area to be 0.
WRITE ANOTHER
TEST
FAILS
func calculateAreaOfRectangle(w: Int, h: Int) -> Double {
return w * h
}
It returns 1
NEW IMPLEMENTATION
func calculateAreaOfRectangle(w: Int, h: Int) -> Double {
    if w > 0 && h > 0 {
        return w * h
    }
    return 0
}
IT PASSED.
REFACTOR
CONTINUE THIS CYCLE UNTIL ALL THE
CRITERIA ARE MET
WHY TDD?
DON’T MISS UNIT-TEST ?
DON’T MISS ANY REQUIREMENT!
FEWER BUGS
High productivity
INTERFACE
FIRST
REFACTORING FRIENDLY
WHAT DOES TDD COST ?
WHEN TDD IS DONE CORRECTLY !
OTHERWISE…
10X OF WORK THAN BEFORE
DO DDT CORRECTLY
TDD
ONLY INTERFACE NEED TO BE TESTED
▸ All the methods not used as interface should be private
TDD
USE GOOD ARCHITECTURE
▸ Less chance for big refactoring
▸ Less chance to destroy the tests
VIP or VIPER
TDD
DO REAL UNIT TEST
▸ What is a unit ?
TDD
Use interface(protocol) to isolate class to test
TDD
Use interface(protocol) to isolate class to test
TDD
let interactor = Interactor()
interactor.presenter = MockPresenter()
Verify function is called with parameter message
interactor.presenter.presentError(message)
verify(interactor.presenter.presentError(message))
TDD
CREATE MOCK MANUALLY OR WITH TOOL
▸ Tool: Cuckoo
▸ https://github.com/Brightify/Cuckoo
▸ Auto-generate mock objects for Swift Protocol
▸ Simulate stub behaviors on each method
▸ Verify if a method is called with certain parameters
TDD
WRITE STRUCTURED TEST
TDD
EFFECTIVE TESTS USING XCTEST
▸ Test_MethodName_StateUnderTest_ExpectedBehavior
Naming convention
TDD
EFFECTIVE TESTS USING XCTEST
Arrange, Act, and Assert
class BananaTests: XCTestCase {
func testPeel() {
// Arrange: Create the banana we'll be peeling.
let banana = Banana()
// Act: Peel the banana.
banana.peel()
// Assert: Verify that the banana is now edible.
XCTAssertTrue(banana.isEdible)
}
}
TDD
STRUCTURE TEST WITH TOOLS
▸ Tool: Quick & Nimble
▸ https://github.com/Quick/Quick
▸ Force developer adding clear comments for each key
section
TDD
STRUCTURE TEST WITH TOOLS
▸ Tool: Quick & Nimble
func testDolphin_click_whenTheDolphinIsNearSomethingInteresting_isEmittedThreeTimes() {
// ...
}
describe("a dolphin") {
describe("its click") {
context("when the dolphin is near something interesting") {
it("is emitted three times") {
// ...
}
}
}
}
TDD
KEY ELEMENTS IN QUICK
▸ describe closure: Describing Classes and Methods 
▸ context closure: Specifying Conditional Behavior
▸ it closure: Assert if requirement is met
describe("a dolphin") {
describe("its click") {
context("when the dolphin is near something interesting") {
it("is emitted three times") {
// verify or assert
}
}
}
}
TDD
REAL-WORLD EXAMPLE ON UNIVADIS
▸ branch: feature/cuckoo
TDD
ARE YOU READY FOR TDD ?

TDD - Test Driven Development in Swift (iOS) with Cuckoo, Quick and Nimble