![Page 1: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/1.jpg)
Always give 100% percent
Jakub Turek19th September, 2018
![Page 2: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/2.jpg)
About me
Jakub Turek
https://jakubturek.com @KubaTurek turekj EL Passion
1
![Page 3: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/3.jpg)
About EL Passion
EL Passion▶ Product house from Warsaw:
▶ UX & UI.▶ Web apps.▶ Native mobile apps.
▶ Core principles:▶ Working closely with clients.▶ All-or-nothing approach to
quality.
2
![Page 4: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/4.jpg)
Agenda
1. Introduction to unit-testing & TDD.2. Engineering for testability.3. iOS testing traps.4. Good engineers’ mistakes.5. Refactoring test code.6. Test code generation.7. Metrics.
3
![Page 5: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/5.jpg)
Motivation
Retrospective of a recent project in numbers:
▶ 3 people.▶ 12 months of work.▶ 217 764 lines of Swift code.▶ 5 811 files.▶ 8 internal frameworks.▶ 7 353 test cases.▶ Hard deadline.
4
![Page 6: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/6.jpg)
Introduction to testing
![Page 7: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/7.jpg)
Unit testing
A unit test is an automated piece of code that invokesa unit of work in the system and then checks a singleassumption about the behavior of that unit of work.
— Roy Osherove, The art of unit testing
5
![Page 8: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/8.jpg)
TDD
TDD is a programming technique which combines wri-ting a test before writing just enough production codeto fulfill that test and refactoring.
— Kent Beck, Test-Driven Development by example
6
![Page 9: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/9.jpg)
Why TDD?
▶ Enables refactoring.▶ Software design discipline.▶ Improved quality:
▶ 15 − 35% increase.▶ 40 − 90% density decrease.
7
![Page 10: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/10.jpg)
TDD workflow
1. Red - write a failing test.2. Green - write minimal amount of code to pass.3. Refactor.
8
![Page 11: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/11.jpg)
3 laws of TDD
1. You can’t write any production code until you writea failing unit test.
2. You can’t write more of a unit test than is sufficient to fail.Not compiling is failing.
3. You can’t write more production code than is sufficient topass currently failing unit test.
9
![Page 12: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/12.jpg)
Demo
10
![Page 13: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/13.jpg)
Engineering for testability
![Page 14: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/14.jpg)
Pure functions
How to write testable code?
1. Pass values to functions.2. Return values from functions.
— @mdiep, Matt Diephouse, Twitter
11
![Page 15: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/15.jpg)
Boundaries
Boundaries by Gary Bernhardt
This talk is about using simple values (as opposed to complexobjects) not just for holding data, but also as the boundariesbetween components and subsystems.
https://destroyallsoftware.com/talks/boundaries
12
![Page 16: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/16.jpg)
Imperative shell, functional core
Imperative shell:
▶ real worlddependencies,
▶ side-effects,▶ stateful operations.
Functional core:
▶ decisions,▶ purely functional
transformations.
13
![Page 17: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/17.jpg)
Demo
14
![Page 18: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/18.jpg)
Resources
Imperative shell, functional core
Detailed demo description, tons of additional resources.
https://jakubturek.com/imperative-shell-functional-core/
15
![Page 19: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/19.jpg)
Dealing with massive controllers
![Page 20: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/20.jpg)
Better MVC
UIViewController , screen. You don’t have tofill the screen. A single screen can show lots ofUIViewControllers.
— Dave DeLong, App Builders 2018
16
![Page 21: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/21.jpg)
More View Controllers
![Page 22: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/22.jpg)
How to decouple controllers?
▶ Never Subclass as a last resort.▶ Use child controllers for composition.▶ Use protocols for controllers’ boundaries.▶ Refer to controllers using compound types
(UIViewController & ControllerProtocol).▶ Expect to reuse controllers.
17
![Page 23: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/23.jpg)
Adding a child controller
func embed(child: UIViewController,inside view: UIView) {
addChildViewController(child)view.addSubview(child.view)child.view.edgeAnchors == view.edgeAnchorschild.didMove(toParentViewController: self)
}
18
![Page 24: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/24.jpg)
Decoupling controllers (1/2)
protocol ChildControllerType: class {var productSelected: ((String) -> Void)? { get set }
}
class ChildController: UIViewController,ChildControllerType {
init(/* dependencies */) { /* ... */ }
var productSelected: ((String) -> Void)?
override func viewDidLoad() {/* implementation */
}}
19
![Page 25: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/25.jpg)
Decoupling controllers (2/2)
typealias ChildControlling =UIViewController & ChildControllerType
class ParentController: UIViewController {init(factory: () -> ChildControlling) {self.factory = factory
}
override func viewDidLoad() {super.viewDidLoad()embed(child: child, inside: view)
}
private lazy var child = factory()private let factory: () -> ChildControlling
} 20
![Page 26: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/26.jpg)
Stubbing a child controller (1/2)
class ChildControllerStub: UIViewController,ChildControllerType {
var productSelected: ((String) -> Void)?}
21
![Page 27: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/27.jpg)
Stubbing a child controller (2/2)
class ParentControllerTests: XCTestCase {var childStub: ChildControllerStub!var sut: ParentController!
override func setUp() {super.setUp()childStub = ChildControllerStub()sut = ParentController(factory: { childStub })
}
func testThatSelectedProductNameIsDisplayed() {childStub.productSelected?("Water")XCTAssertEqual(sut.view.label.text, "Water")
}}
22
![Page 28: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/28.jpg)
Examples
▶ Buttons.▶ Forms fields.▶ API data coordination with immutable children.
23
![Page 29: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/29.jpg)
Our metrics
▶ Longest file (controller) in a project: 140 lines.▶ Controllers in total: 164.▶ Screens in total: 38.▶ Average 4.32 controller per screen.▶ Average 75.16 lines of code per controller.
24
![Page 30: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/30.jpg)
Views
![Page 31: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/31.jpg)
iOSSnapshotTestCase
iOSSnapshotTestCase
iOSSnapshotTestCase takes preconfigured view andrenders its snapshot. It compares snapshot to a “referenceimage” stored in repository and fails if the two images don’tmatch.
https://github.com/uber/ios-snapshot-test-case
25
![Page 32: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/32.jpg)
iOSSnapshotTestCase diff
Expected Actual
Diff
26
![Page 33: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/33.jpg)
Instant feedback for views
![Page 34: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/34.jpg)
Red phase (1/3)
Note down the size from design (≈ 300 × 40).
27
![Page 35: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/35.jpg)
Red phase (2/3)
override func setUp() {super.setUp()recordMode = true
sut = GradientLabelView(text: "Academia Gorila")sut.frame = CGRect(width: 300, height: 40)
}
func testLabelMatchesSnapshot() {FBSnapshotVerifyView(sut)
}
class GradientLabelView { // ... implementation }
28
![Page 36: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/36.jpg)
Red phase (3/3)
Build the view in iterations:
1. Change the code.2. Run the tests.3. Compare a reference image to the design:
▶ Repeat the cycle if needed.
29
![Page 37: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/37.jpg)
Green phase
override func setUp() {super.setUp()recordMode = false
sut = GradientLabelView(text: "Academia Gorila")sut.frame = CGRect(width: 300, height: 40)
}
func testLabelMatchesSnapshot() {FBSnapshotVerifyView(sut)
}
30
![Page 38: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/38.jpg)
Refactor phase
▶ Move the view to a production target.▶ Refactor the view.
31
![Page 39: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/39.jpg)
Global methods
![Page 40: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/40.jpg)
Global method example
static func drawImage(of size: CGSize,using drawer: (CGContext) -> Void)-> UIImage? {
UIGraphicsBeginImage...(size, false, 0.0)
defer { UIGraphicsEndImageContext() }
guard let ctx = UIGraphicsGetCurrentContext() else {return nil
}
drawer(ctx)
return UIGraphicsGetImage...()}
32
![Page 41: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/41.jpg)
Swift namespace resolution (1/2)
Shipping your own controller type:
class UIViewController {func theTimeHasComeToLoadAView() {myOwnPersonalView = SomeView()
}}
let controller = UIViewController()controller.theTimeHasComeToLoadAView() // works
33
![Page 42: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/42.jpg)
Swift namespace resolution (2/2)
Shipping your own controller library:
# Podfilepod 'MyOwnController', '~> 0.1'
// SourceFile.swiftimport MyOwnControllerimport UIKit
UIViewController() // compilation error
34
![Page 43: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/43.jpg)
Testing global methods (1/2)
import UIKit
func UIGraphicsGetImageFromCurrentImageContext()-> UIImage? {
return imageFromContext()}
var imageFromContext: () -> UIImage? =UIKit.UIGraphicsGetImageFromCurrentImageContext
35
![Page 44: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/44.jpg)
Testing global methods (2/2)
override func setUp() {imageFromContext = { UIImage.catMeme }
}
override func tearDown() {imageFromContext = UIKit.UIGraphicsGetImage...
}
func testThatDrawImageReturnsImageFromContext() {let image = CGContext.drawImage(of: .zero) { _ in }
XCTAssertEqual(UIImagePNGRepresentation(image),UIImagePNGRepresentation(imageFromContext())
)} 36
![Page 45: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/45.jpg)
Apple
![Page 46: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/46.jpg)
Push notifications (1/2)
open class UNNotificationSettings: NSObject,NSCopying,NSSecureCoding {
open var authorizationStatus:UNAuthorizationStatus { get }
public init?(coder aDecoder: NSCoder)// NS_DESIGNATED_INITIALIZER
}
37
![Page 47: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/47.jpg)
Push notifications (2/2)
class DecoderFake: NSCoder {override func decodeInt64(forKey _: String) -> Int64 {return 0
}
override func decodeBool(forKey _: String) -> Bool {return false
}
override func decodeObject() -> Any? {return nil
}
override var allowsKeyedCoding: Bool {return false
}}
38
![Page 48: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/48.jpg)
Good engineer’s mistakes
![Page 49: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/49.jpg)
Stubbing to death
Mock across architecturally significant boundaries, butnot within those boundaries.
— Robert C. Martin, When to Mock
39
![Page 50: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/50.jpg)
Overmocking (1/3)
class URLBuilderSpy: URLBuilding {private(set) var routeSpy: [(String, ImageType)] = []
func route(forImageWithURL imageURL: String,of type: ImageType) throws -> URL {
routeSpy.append((imageURL, type))return URL(string: "https://google.com")!
}}
40
![Page 51: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/51.jpg)
Overmocking (2/3)
class ImageFetcherSpy: ImageFetching {private(set) var imageSpy: [URL] = []
func image(for url: URL) -> Single<UIImage> {imageSpy.append(url)return Single.just(UIImage.testImage)
}}
41
![Page 52: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/52.jpg)
Overmocking (3/3)
var urlBuilderSpy: URLBuilderSpy!var fetcherSpy: ImageFetcherSpy!
func testThatAvatarsAreFetched() {let images = try! sut.fetchAvatars()
.toBlocking().first()
XCTAssertEqual(["one", "two"],urlBuilderSpy.routeSpy.map { $0.0 })
XCTAssertEqual([.userAvatar, .userAvatar],urlBuilderSpy.map { $0.1 })
XCTAssertEqual([URL.google, URL.google],fetcherSpy.imageSpy)
XCTAssertImages([.testImage, .testImage], images)}
42
![Page 53: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/53.jpg)
Maintaining unreliable tests
![Page 54: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/54.jpg)
Unit test
Good unit test is:
▶ automated,▶ fast,▶ tests a single logical concept in the system,▶ trustworthy.
43
![Page 55: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/55.jpg)
Keeping false positives
Unreliable tests
A single false positive will eventually kill the purpose ofthousands meaningful tests in a suite.
44
![Page 56: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/56.jpg)
Refactoring test code
![Page 57: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/57.jpg)
Testing models (1/2)
struct User {let id: Intlet born: Date
}
45
![Page 58: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/58.jpg)
Testing models (2/2)
func testThatUsersBornInJanuaryGetAPrize() {let u1 = User(id: 3,born: Date(timeIntervalSince1970: 631886400)
)let u2 = User(id: 6,born: Date(timeIntervalSince1970: 634233600)
)let u3 = User(id: 8,born: Date(timeIntervalSince1970: 727466400)
)
XCTAssertEqual(sut.winners([u1, u2, u3]), [3, 8])} 46
![Page 59: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/59.jpg)
Test data
extension User {static var bornJanuary1990: User {return User(id: 3, born: "1990-01-09 12:00".date())
}
static var bornFebruary1990: User {return User(id: 6, born: "1990-02-05 16:00".date())
}
static var bornJanuary1993: User {return User(id: 8, born: "1993-01-19 18:00".date())
}}
47
![Page 60: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/60.jpg)
Refactored tests
func testThatUsersBornInJanuaryGetAPrize() {let winnerIDs = sut.winners([.bornJanuary1990,.bornFebruary1990,.bornJanuary1993
])
XCTAssertEqual(winnerIDs, [3, 8])}
48
![Page 61: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/61.jpg)
Test code generation
![Page 62: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/62.jpg)
Sourcery
Sourcery
Sourcery is a code generator for Swift language, built on top ofApple’s own SourceKit. It extends the language abstractions toallow you to generate boilerplate code automatically.
https://github.com/krzysztofzablocki/Sourcery
49
![Page 63: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/63.jpg)
Problem: required initializers
0% code coverage when not using inteface builder
required init?(coder aDecoder: NSCoder) {return nil
}
50
![Page 64: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/64.jpg)
AllViews.stencil
extension UIView {
static var allInitializers: [(NSCoder) -> UIView?] {return [{% for view in types.classes where view.based.UIView %}{% set spacer %}{% if not forloop.last %},{% endif %}{% endset %}{% for initializer in view.initializers %}{% if initializer.selectorName == "init(coder:)" %}{{ view.name }}.init(coder:){{ spacer }}{% endif %}{% endfor %}{% endfor %}]
}
}
51
![Page 65: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/65.jpg)
AllViews.generated.swift
extension UIView {
static var allInitializers: [(NSCoder) -> UIView?] {return [
ActionBarView.init(coder:),AuthorizeErrorView.init(coder:),BlurView.init(coder:),BorderedButtonView.init(coder:),FilterView.init(coder:),HeaderView.init(coder:),/* ... */
]}
}
52
![Page 66: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/66.jpg)
AllViewsTests.swift
func testThatAllViewsAreNonCodable() {UIView.allInitializers.forEach { initializer inXCTAssertNil(initializer(NSCoder()))
}}
53
![Page 67: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/67.jpg)
Other usages
▶ Automatic synthesizing of Equatable conformance inextensions.
▶ Mock object generation.▶ Complex assertions:
▶ There is a factory class for every Route.▶ There is an integration test for every request.
54
![Page 68: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/68.jpg)
Metrics
![Page 69: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/69.jpg)
Metrics
Measured on every pull request:
▶ Project size:▶ lines of code,▶ files count,▶ average file size.
▶ Static analysis:▶ SwiftLint: consistent coding style,▶ jscpd: automatic copy-paste detection.
▶ Code coverage.
55
![Page 70: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/70.jpg)
Metrics - visualization
Danger
Danger runs during your CI process, and gives teams thechance to automate common code review chores.
http://danger.systems/js/swift.html
56
![Page 71: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/71.jpg)
Danger
57
![Page 72: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/72.jpg)
Automatic copy-paste detection
JSCPD
jscpd is a tool for detect copy/paste ”design pattern” inprogramming source code.
https://github.com/kucherenko/jscpd
58
![Page 73: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/73.jpg)
JSCPD + Danger = (1/3)
59
![Page 74: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/74.jpg)
JSCPD + Danger = (2/3)
cpd.yaml:
languages:- swift
files:- "Sources/**"
exclude:- "**/*.generated.swift"
reporter: jsonoutput: jscpd_report.json
60
![Page 75: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/75.jpg)
JSCPD + Danger = (3/3)
Dangerfile:
def find_duplicates`jscpd`
rep = JSON.parse(File.read('jscpd_report.json'))clones = rep["statistics"]["clones"]
if clones > 0warn("JSCPD found #{clones} clone(s)")
endend
Full version: https://tinyurl.com/yc23t4mb
61
![Page 76: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/76.jpg)
Code coverage
Code coverage is a percentage of code which is covered byautomated tests.
Test coverage is a useful tool for finding untested partsof a codebase. Test coverage is of little use as a numericstatement of how good your tests are.
— Martin Fowler, TestCoverage
62
![Page 77: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/77.jpg)
danger-xcov (1/2)
danger-xcov
danger-xcov is the Danger plugin of xcov, a friendlyvisualizer for Xcode’s code coverage files.
https://github.com/nakiostudio/danger-xcov
63
![Page 78: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/78.jpg)
danger-xcov (2/2)
64
![Page 79: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/79.jpg)
Thank you!
65
![Page 80: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/80.jpg)
Additional resources
Jakub TurekAlways give one hundred percenthttps://jakubturek.com/talks/
Jon ReidQuality Coding - Bloghttps://qualitycoding.org/blog/
Kasper B. GraversenGist: functional core, imperative shellhttps://tinyurl.com/y9cxblm8
66
![Page 81: Always give 100% percent - Jakub Turek · Unit testing A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about](https://reader033.vdocuments.net/reader033/viewer/2022053006/5f09dd887e708231d428de77/html5/thumbnails/81.jpg)
Feedback
@elpassion
67