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

Unit testings in Swift

Unit testings in Swift

Mark Wilkinson

March 30, 2016
Tweet

More Decks by Mark Wilkinson

Other Decks in Technology

Transcript

  1. Unit Testing in Swift
    or what I learned after getting it wrong a lot.

    View Slide

  2. What we’ll cover
    What is a Unit Test and what is TDD
    Gotchas with Xcode and Testing
    What I used to do in obj-c and what I learned to do
    better in Swift
    real-world coding example of starting a Swift app with
    testing

    View Slide

  3. Unit testing is a development process in which the
    smallest testable parts of an application, called units,
    are individually and independently scrutinized for
    proper operation.
    Test-driven development (TDD) is a software
    development process that relies on the repetition of a
    very short development cycle: first the developer
    writes an (initially failing) automated test case that
    defines a desired improvement or new function, then
    produces the minimum amount of code to pass that
    test

    View Slide

  4. Unit Testing with Xcode has changed a little in each
    version.
    You could get away with more things like forcing views
    to load (to test your viewDidLoad logic)
    Objective-C was less restrictive in things being a
    dynamic language.
    Apple originally had no interest (it seemed) in the Unit
    Testing/TDD world, and did not get involved until iOS 7

    View Slide

  5. New rules with Xcode 7 and Swift
    If you get this error,
    Do this,
    Start using @testable

    View Slide

  6. In Objective-C we had OCUnit and OCMock

    View Slide

  7. Had to pull in all kinds of headers when testing a
    complex UIViewController

    View Slide

  8. In Swift now you just pull in the module of
    your app target
    Every test class you make now comes with a
    reminder to test performance.

    View Slide

  9. Most of your testing focus should be on
    ViewControllers
    in fact, your testing should start at the
    ViewController (one test class per each)
    and then refactoring will give you a model
    and service layer.

    View Slide

  10. But how do you handle networking, Core Data, etc?
    Simple answer…
    you don’t
    or at least not directly in the ViewControllers

    View Slide

  11. In most cases especially with networking,
    you’ll want to use a mock and/or stubbed
    replacement for the service.
    For CoreData you can test with a real stack
    but you need to clean the storage out after
    each run of the test suite, this is where the
    tearDown() method comes in handy.

    View Slide

  12. TDD and unit testing in general don’t work
    with tightly-coupled architectures.
    in fact there will probably be little you can
    test if separation of concerns and
    responsibilities are not assigned properly
    This is the silver-lining of unit testing, you
    enforce better coding practices the more
    you can test your app.

    View Slide

  13. Lets create a quick viewController test
    suite

    View Slide

  14. Layout your requirements first.
    Then form those into failing tests.
    1) Title in Navigation Bar (according to
    specs) should say “Magenic Mobile”
    2) Navigation Bar color should be red

    View Slide

  15. Lets instantiate the ViewController, then
    make our first failing test case.

    View Slide

  16. As we expected, it failed, in fact it should
    always fail first if you’re doing Test-First

    View Slide

  17. Still not passing…
    Now comes the dilemma, what do I do to
    force the view to load, layout, etc. ?

    View Slide

  18. In Obj-C world you could just call loadView
    or directly call viewDidLoad
    Apple has specifically said now in
    documentation to not do either of those
    things in tests, instead just call the getter of
    the view.
    https://www.natashatherobot.com/ios-testing-view-controllers-swift/

    View Slide

  19. View Slide

  20. Next expectation was a navigation bar
    color…
    hmm… no navbar to be found, or
    Navigation Controller.

    View Slide

  21. First rule of TDD!?
    write the failing test before attempting to
    solve the problem.
    To make this pass we’ll have to change how
    we created the viewController in setup()

    View Slide

  22. remember we have a Navigation Controller
    starting off the workflow in the storyboard

    View Slide

  23. Not the best way to set the bar background
    color especially (as in most cases) the
    color is needed for the whole app.
    Step 1, fail it
    Step 2, pass it
    Step 3, refactor it

    View Slide

  24. Now just update your setup code again to
    grab that appearance proxy usage
    Doh! Now it’s failing again…

    View Slide

  25. Now the hard part, how to deal with
    external dependencies
    There’s probably an infinite number of
    opinionated ways to do this.
    Make a mock, don’t use a mock, call a real
    service, etc.
    Mocks and Stubs have always worked for
    me in C# so I’ll stick with that.

    View Slide

  26. First off, we know we’ll have a network call
    to get a list of mobile group members.
    The key is to know what format is coming
    back, XML or JSON
    Then build a mock and stubbed service to
    emulate the behavior
    Once it’s fully emulated you can verify
    everything about the data, how to display
    it, how to parse it, etc.

    View Slide

  27. The key to mocking and stubbing is to use
    a protocol

    View Slide

  28. In this simple contrived example we’re
    really just making a stub, a mock is really
    about verifying behavior.
    If you want to add some mock behavior,
    you can add flags for each method called.
    the flag is the mock behavior, the return of
    canned values is the stubbed behavior

    View Slide

  29. Add the protocol (not the MyService class)
    as a property to your ViewController

    View Slide

  30. Update your setup code to now inject this
    mock dependency
    It’s important that you do the dependency
    injection before you call the view, because

    View Slide

  31. Now verify with the mock (flagged)
    behavior with a test
    Now is a good time to use tearDown to
    reset the flag

    View Slide

  32. That was a mock test, how about a stub?
    Yes, you can directly call the
    UITableViewDelegate and datasource
    methods in tests.

    View Slide

  33. Now to make that test pass, code like you
    normally would if the service responded
    back with a set of strings.

    View Slide

  34. Hand-rolling your own mocks for the
    purpose of unit-testing is tedious and time
    consuming.
    Yes you can use some third-party mocking
    libraries, and if you only plan on using
    mocks for testing, I’d recommend that
    approach.
    But, I’d recommend doing the first
    approach with manually creating your
    mock classes that also stub out responses
    You get the added benefit of an offline
    service to test your app when the service is
    down

    View Slide

  35. View Slide