Slide 1

Slide 1 text

Unit Testing WTWs (What the WOWs !!!) !

Slide 2

Slide 2 text

A tale about what surprised me while unit testing...

Slide 3

Slide 3 text

#0 !"#

Slide 4

Slide 4 text

There is always a 1/2

Slide 5

Slide 5 text

Who has never written a unit test in Xcode?

Slide 6

Slide 6 text

Who has !ever written a unit test in Xcode?

Slide 7

Slide 7 text

I have met 3 types of programmers · a few ones that say unit testing is cool ❤

Slide 8

Slide 8 text

I have met 3 types of programmers · majority that say real men ! test on PROD

Slide 9

Slide 9 text

I have met 3 types of programmers · some that don't know how the ! can they start doing it?

Slide 10

Slide 10 text

# 1 WT! a unit test is?

Slide 11

Slide 11 text

Standard bla bla bla... In computer programming, unit testing is a so!ware testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use. — Wikipedia

Slide 12

Slide 12 text

code that tests source code

Slide 13

Slide 13 text

WT! a unit test is?

Slide 14

Slide 14 text

WT! a unit test is? · App = set of behaviours !"

Slide 15

Slide 15 text

WT! a unit test is? · App = component ! + ... + component !

Slide 16

Slide 16 text

WT! a unit test is? · component ← interaction ! → component

Slide 17

Slide 17 text

WT! a unit test is? · unit test = checks(! ← interaction " → !) == ✅

Slide 18

Slide 18 text

Let's write down example behaviours !"

Slide 19

Slide 19 text

WT! a unit test is? "BluetoothModule" "when turned on" "advertises services" "when turned off" "doesn't advertise services"

Slide 20

Slide 20 text

# 2 What the ! spec?!

Slide 21

Slide 21 text

What the ! spec?! · specification ! of our source code

Slide 22

Slide 22 text

What the ! spec?! · spec contains assertions ! (testing code)

Slide 23

Slide 23 text

What the ! spec?! · Use Quick and its ! DSL to create a spec

Slide 24

Slide 24 text

What the ! spec?! · Quick - BDD framework · Nimble - set of matchers

Slide 25

Slide 25 text

What the ! spec?! context("BluetoothModule") { describe("when turned on") { it("advertises services") {} } describe("when turned off") { it("doesn't advertise services") {} } }

Slide 26

Slide 26 text

What the ! spec?! import Quick import Nimble @testable import <#Module#> class <#TestedClass#>Spec: QuickSpec { override func spec() { //!Magic goes here "#$ } }

Slide 27

Slide 27 text

What the ! spec?! Arrange, Act, Assert

Slide 28

Slide 28 text

Arrange, Act, Assert class BluetoothModule { init(peripheralManager: CBPeripheralManagerProtocol) func turnOn() func turnOff() }

Slide 29

Slide 29 text

Arrange phase ! All the world's a stage, ... — Shakespeare !

Slide 30

Slide 30 text

Arrange phase class BluetoothModuleSpec: QuickSpec { override func spec() { context("BluetoothModule") { //i.e. newly initialized var sut: BluetoothModule! var peripheralManager: CBPeripheralManagerProtocol! beforeEach { peripheralManager = MockPeripheralManager() sut = BluetoothModule(peripheralManager: peripheralManager) } afterEach { peripheralManager = nil sut = nil } } } }

Slide 31

Slide 31 text

Arrange phase · context - description of object's state (e.g. object is newly initialised) · beforeEach - local variables setup (XCTest's setup) · a!erEach - local variables cleanup (XCTest's tearDown)

Slide 32

Slide 32 text

Act phase ! ... And all the men and women merely players ... — Shakespeare !

Slide 33

Slide 33 text

Act phase context("BluetoothModule") { //... describe("when turned on") { beforeEach { sut.turnOn() } } describe("when turned off") { beforeEach { sut.turnOff() } } }

Slide 34

Slide 34 text

Act phase · describe - description of action performed on the subject · beforeEach - action on the sut (subject of unit testing)

Slide 35

Slide 35 text

Assert phase ! XCTAssert(true, "Here Shakespeare's quote doesn't fit") — Maciej Piotrowski !

Slide 36

Slide 36 text

Assert phase context("BluetoothModule") { describe("when turned on") { //... it("advertises services") { expect(peripheralManager.isAdvertising) .to(beTrue()) } } }

Slide 37

Slide 37 text

Assert phase context("BluetoothModule") { describe("when turned off") { //... it("advertises services") { expect(peripheralManager.isAdvertising) .to(beFalse()) } } }

Slide 38

Slide 38 text

Assert phase · it - description of desired outcome and test of an expected behaviour

Slide 39

Slide 39 text

#3 What to ! expect?

Slide 40

Slide 40 text

Expect the unexpected...

Slide 41

Slide 41 text

What to ! expect? · Nimble ! provides a number of matchers · Matchers are used in it blocks to assert the expectation ✅

Slide 42

Slide 42 text

What to ! expect? expect(sut.something) .to(equal(5)) expect(sut.somethingDifferent) .toNot(beAKindOf(MyClass)) expect(sut.somethingElse) .toEventually(beNil())

Slide 43

Slide 43 text

What to ! expect? extension MyClass: Equatable {} func ==(lhs: MyClass, rhs: MyClass) -> Bool { return lhs.propertyX == rhs.propertyX && lhs.propertyY == rhs.propertyY && lhs.propertyZ == rhs.propertyZ }

Slide 44

Slide 44 text

What to ! expect? extension MyClass: Equatable {} func ==(lhs: MyClass, rhs: MyClass) -> Bool { return ObjectIdetifier(lhs) == ObjectIdentifier(rhs) }

Slide 45

Slide 45 text

What to ! expect? class class1: NSObject {} class class2: NSObject {} let c1 = class1() let c2 = class2() it("should not be equal") { expect(c1).toNot(equal(c2)) }

Slide 46

Slide 46 text

What to ! expect? it("should be equal") { expect(peripheralManager.delegate as? SDBluetoothModule).to(equal(sut)) }

Slide 47

Slide 47 text

#4 I wish we had mockingjays !

Slide 48

Slide 48 text

What's a Mock?

Slide 49

Slide 49 text

Inject test doubles as dependencies

Slide 50

Slide 50 text

stub - fakes a response to method call

Slide 51

Slide 51 text

mock - lets to check if a call is performed

Slide 52

Slide 52 text

partial mock - actual object altered a bit (some responses faked, some not)

Slide 53

Slide 53 text

W!W. Out of the box mocks are not possible in Swift

Slide 54

Slide 54 text

Swift is currently read-only !

Slide 55

Slide 55 text

There is no way to change class types & objects at run time

Slide 56

Slide 56 text

Communicate with objects through protocols

Slide 57

Slide 57 text

What's a Mock? protocol CBPeripheralManagerProtocol: class { //... weak var delegate: CBPeripheralManagerDelegate { get set } func startAdvertising() func stopAdvertising() }

Slide 58

Slide 58 text

If you don't you will end up with inheritance and partial mocks, which is not recommended...

Slide 59

Slide 59 text

What's a Mock? class MockCBPeripheralManager: CBPeripheralManagerProtocol { //... var startAdvertisingCount = 0 func startAdvertising() { startAdvertisingCount += 1 } }

Slide 60

Slide 60 text

What's a Mock? context("BluetoothModule") { describe("when turned on") { //... it("advertises services") { expect(peripheralManager.startAdvertisingCount) .to(equal(1)) } } }

Slide 61

Slide 61 text

#5 ! Unit test all the things!

Slide 62

Slide 62 text

and mainly interactions between objects

Slide 63

Slide 63 text

But I like to test view controllers!

Slide 64

Slide 64 text

Unit test all the things! ! context("ViewController") { describe("when view loads") { beforeEach { sut.viewDidLoad() } it("does sth") { expect(sut.didSomething).to(beTrue()) } } }

Slide 65

Slide 65 text

What to test?

Slide 66

Slide 66 text

Check if appropriate buttons are set on navigationItem

Slide 67

Slide 67 text

Unit test all the things! ! it("has right button") { expect(sut.navigationItem.rightBarButtonItem) .to(beAKindOf(UIBarButtonItem)) expect(sut.navigationItem.rightBarButtonItem?.enabled) .to(beTrue()) }

Slide 68

Slide 68 text

Check if view controller is tableView's or collectionView's delegate

Slide 69

Slide 69 text

Unit test all the things! ! expect(sut.tableView.delegate as? MyViewController).to(equal(sut)) expect(sut.collectionView.delegate as? MyViewController).to(equal(sut))

Slide 70

Slide 70 text

Check if a tap on a button shows a new view controller

Slide 71

Slide 71 text

Unit test all the things! ! Unit Test Helper comes in handy class UnitTestHelper { class func presentViewControllerModally(vc: UIViewController) {} class func tap(button: UIButton?) {} class func tap(button: UIBarButtonItem?) {} //... }

Slide 72

Slide 72 text

Unit test all the things! ! describe("tap on the right button") { beforeEach { Helper.tap(sut.navigationItem.rightBarButtonItem) } it("shows my other view controller") { expect(sut.presentedViewController) .toEventually(beAKindOf(MyOtherViewController)) } }

Slide 73

Slide 73 text

#6 Do pure Swift objects have load() ?! !

Slide 74

Slide 74 text

Do pure Swift objects have load() ?! ! class MyViewModel { func load() {} } class MyViewController: UIViewController { let viewModel = MyViewModel() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.whiteColor() viewModel.load() } }

Slide 75

Slide 75 text

Do pure Swift objects have load() ?! ! describe("when view loads") { beforeEach { sut.viewDidLoad() } it("calls load on viewModel") { expect(viewModel.loadCount) .to(equal(1)) //ASSERTION FAILURE: expected 1, got 2 } }

Slide 76

Slide 76 text

Do pure Swi! objects have load method?!

Slide 77

Slide 77 text

Do pure Swift objects have load() ?! ! //The view controller calls this method //when its view property is requested but is currently nil. func loadView()

Slide 78

Slide 78 text

What's called a!er loadView?

Slide 79

Slide 79 text

The viewDidLoad method.

Slide 80

Slide 80 text

Do pure Swift objects have load method?! !

Slide 81

Slide 81 text

Pure Swi! objects don't have load method.

Slide 82

Slide 82 text

#7 What is it all f!r ?

Slide 83

Slide 83 text

Testing is not common in iOS development

Slide 84

Slide 84 text

What is it all f!r ? · better understanding ! a codebase

Slide 85

Slide 85 text

What is it all f!r ? · ! well thought architecture

Slide 86

Slide 86 text

What is it all f!r ? · properly documented assumptions !

Slide 87

Slide 87 text

What is it all f!r ? · no fear of making changes !

Slide 88

Slide 88 text

What is it all f!r ? · getting to know ! Apple frameworks better

Slide 89

Slide 89 text

❤ for fun !!! ❤

Slide 90

Slide 90 text

The time to write unit tests is now.

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

Resources · swi!ing.io - code quality and unit testing · Paweł Dudek - BDD presentastions · objc.io - issue #15 · realm.io - Real-world mocking in Swi!