$30 off During Our Annual Pro Sale. View Details »

Unit Testing in iOS

Khoa Pham
September 06, 2019

Unit Testing in iOS

I talk about unit testing in iOS and best practices

Khoa Pham

September 06, 2019
Tweet

More Decks by Khoa Pham

Other Decks in Programming

Transcript

  1. Unit Testing in
    iOS

    View Slide

  2. About
    → Khoa Pham
    → onmyway133.github.io

    View Slide

  3. View Slide

  4. Unit Test
    → What
    → Why
    → How
    → Good Pratices

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  8. Code from others

    View Slide

  9. Complex operation

    View Slide

  10. Complex control flow

    View Slide

  11. Assumption

    View Slide

  12. Edge cases

    View Slide

  13. XCTest
    → Unit tests
    → Performance tests
    → UI tests

    View Slide

  14. 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"
    }

    View Slide

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

    View Slide

  16. 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

    View Slide

  17. 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))
    }
    }

    View Slide

  18. 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")
    }
    }

    View Slide

  19. 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.

    View Slide

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

    View Slide

  21. 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

    View Slide

  22. Good practices

    View Slide

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

    View Slide

  24. View Slide

  25. 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)
    }
    }

    View Slide

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

    View Slide

  27. View Slide

  28. 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()
    }

    View Slide

  29. View Slide

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

    View Slide

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

    View Slide

  32. View Slide

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

    View Slide

  34. View Slide

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

    View Slide

  36. View Slide

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

    View Slide

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

    View Slide

  39. 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

    View Slide