Slide 1

Slide 1 text

Unit Testing in iOS

Slide 2

Slide 2 text

About → Khoa Pham → onmyway133.github.io

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Unit Test → What → Why → How → Good Pratices

Slide 5

Slide 5 text

F.I.R.S.T. → Fast → Independent → Repeatable → Self validating → Timely

Slide 6

Slide 6 text

What Unit test is code that tests a unit of code. → Automate → Trustworthy → Examine all possible cases

Slide 7

Slide 7 text

Why → Verify → Act as documentation → Decouple components → Avoid regression bugs → Refactoring

Slide 8

Slide 8 text

Code from others

Slide 9

Slide 9 text

Complex operation

Slide 10

Slide 10 text

Complex control flow

Slide 11

Slide 11 text

Assumption

Slide 12

Slide 12 text

Edge cases

Slide 13

Slide 13 text

XCTest → Unit tests → Performance tests → UI tests

Slide 14

Slide 14 text

Property testing property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in return (xs.reverse().reverse() == xs) > "Left identity" ^&&^ (xs == xs.reverse().reverse()) > "Right identity" }

Slide 15

Slide 15 text

Snapshot testing class MyViewControllerTests: XCTestCase { func testMyViewController() { let vc = MyViewController() assertSnapshot(matching: vc, as: .image) } }

Slide 16

Slide 16 text

BDD style → Behavior driven developmennt → RSpec describe HelloWorld do context “When testing the HelloWorld class” do it "should say 'Hello World' when we call the say_hello method" do hw = HelloWorld.new message = hw.say_hello expect(message).to eq "Hello World!" end end end

Slide 17

Slide 17 text

BDD in Swift context("a move that was already played") { it("should throw an error") { try! board.play(at: 0) // 1 // 2 expect { try board.play(at: 0) } .to(throwError(Board.PlayError.alreadyPlayed)) } }

Slide 18

Slide 18 text

XCTest class HourFormatterTests: XCTestCase { func testFormat() { let formatter = HourFormatter() XCTAssertEqual(formatter.format(minute: 90 ), "01:30") XCTAssertEqual(formatter.format(minute: 120), "02:00") XCTAssertEqual(formatter.format(minute: 660 ), "11:00") } }

Slide 19

Slide 19 text

TDD → Test driven development → TDD is dead. Long live testing https://dhh.dk/ 2014/tdd-is-dead-long-live-testing.html Less emphasis on unit tests, because we're no longer doing test-first as a design practice, and more emphasis on, yes, slow, system tests.

Slide 20

Slide 20 text

Cons of unit test → Take time → Code change → Take time → Compromised test → Take time

Slide 21

Slide 21 text

Still → It's good to have unit test → Does not matter if TDD or not. As long as we have tests → Validate quickly and reliably → Help your future self or other maintainers

Slide 22

Slide 22 text

Good practices

Slide 23

Slide 23 text

1. Test alongside code → Jest https://jestjs.io/

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

2. Test what you feel need import XCTest @testable import Cutters_Staging class LauncScreenTests: XCTestCase { func testLaunchScreen() { let launchScreen = UIStoryboard(name: "LaunchScreen", bundle: nil) let viewController = launchScreen.instantiateInitialViewController()! let label = viewController.view.subviews.compactMap({ $0 as? UILabel }).first! XCTAssertEqual(label.text, "Cut time. Cut hair. Cut cost.") let imageView = viewController.view.subviews.compactMap({ $0 as? UIImageView }).first! XCTAssertNotNil(imageView.image) } }

Slide 26

Slide 26 text

3. View be dumb → Decouple representation (view) from computation (logic) → Model - View - Controller → Test logic → And can also test UI

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

4. Mock → Mock during development → Mock during testing final class Deps { static let salonRepo: SalonRepoAware = SalonRepo() static let userRepo: UserRepoAware = UserRepo() static let cardRepo: CardRepoAware = CardRepo() }

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

5. Commit hook → pre-commit marker="" test $(git diff --cached -z $against | grep $marker | wc -c) != 0

Slide 31

Slide 31 text

6. Coverage → Code coverage != Test coverage → 100% code coverage

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

7. Continuous integration → Jenkins → Bitrise → Circle → Xcode Server

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

8. Xcode → XCTWaiter Xcode 8.3 → XCUISiriService in Xcode 9 → Parallel testing Xcode 10 → XCTestPlan Xcode 11 → Simulation, random order, attachment, activity, ...

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

$ xcodebuild test -scheme MyApp \ -destination "plaform=iOS,name=iPhone 8" \ -destination "platform=iOS,name=iPhone 8 Plus"

Slide 38

Slide 38 text

One more thing https://www.youtube.com/watch?v=D-dj_cwdVYg

Slide 39

Slide 39 text

Thank you M̶a̶y̶ ̶t̶h̶e̶ ̶f ̶o̶r̶c̶e̶ ̶b̶e̶ ̶w̶ i ̶ t̶h̶ ̶y̶o̶u̶ May your code continue to compile