Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Practical Testing Tips - iOS Con London, May 2016

Practical Testing Tips - iOS Con London, May 2016

The London 2016 Edition of my smorgasboard of unit and UI testing tips. Links to sample code at the end of the presentation.

Ellen Shapiro
PRO

May 26, 2016
Tweet

More Decks by Ellen Shapiro

Other Decks in Technology

Transcript

  1. PRACTICAL
    TESTING TIPS
    by Ellen Shapiro | ios con London 2016
    spothero.com | justhum.com | designatednerd.com | @designatednerd

    View Slide

  2. Why
    don't developers
    write tests?

    View Slide

  3. "I Don't have time
    to Write tests"

    View Slide

  4. Writing Tests lets you
    refactor faster
    and with more confidence

    View Slide

  5. Writing tests puts your time costs
    up front

    View Slide

  6. Writing tests catches your mistakes
    as you make them

    View Slide

  7. "I Have No idea
    where to start"

    View Slide

  8. [ Demo: Super-Basic Testing ]

    View Slide

  9. What
    should you test?

    View Slide

  10. Test The Stuff That
    Breaks A Lot

    View Slide

  11. "That's called
    software."

    View Slide

  12. Test The Stuff That
    is easier for a robot
    than for you to test

    View Slide

  13. Your computer is an
    awesome robot
    you can use to do
    your evil bidding.

    View Slide

  14. [ Demo: Time Converter 24 ]

    View Slide

  15. Test The Stuff That
    is mission-critical

    View Slide

  16. if it breaks, will your users do this?

    View Slide

  17. [ Demo: Core data testing ]

    View Slide

  18. View Slide

  19. Core Data Demo Recap
    » When you see something that can cause a key piece
    of your app to break, test it.
    » When testing core data, test the
    NSInMemoryStoreType so you always have a clean
    database.
    » Version your databases!

    View Slide

  20. Test The Stuff That
    Depends On Someone Else

    View Slide

  21. Is it my code?
    or
    Is it their code?

    View Slide

  22. Test it with something that
    looks like the real thing.

    View Slide

  23. Mock testing

    View Slide

  24. Verifying
    Did this do what it was supposed to?

    View Slide

  25. Stubbing
    Fake it 'til you make it

    View Slide

  26. Spying
    Faking PART of an object

    View Slide

  27. Objective-C Mocking tools
    OCMock
    OCMockito

    View Slide

  28. [ Demo: Making a Mockery ]

    View Slide

  29. Objective-C Mock Demo Recap
    » Make a fake thing
    » Tell it what to do
    » Pass it to the thing you want to test
    » Make sure the tested thing reacted properly

    View Slide

  30. Mocking in swift

    View Slide

  31. Swift Inline Class Verification
    func testThingDoesStuff() {
    class MockThing : Thing {
    var methodUnderTestWasCalled = false
    override func methodUnderTest() {
    //Don't call super!
    methodUnderTestWasCalled = true
    }
    }
    let testThing = MockThing()
    testThing.doSomethingThatShouldCallMethodUnderTest()
    XCTAssertTrue(testThing.methodUnderTestWasCalled)
    }

    View Slide

  32. Swift Inline Class Stubs/Spies
    func testThingDoesStuff() {
    class StubbedThing : Thing {
    override func methodBeingStubbed() -> String {
    //Don't call super!
    return "A Known String!"
    }
    }
    let stub = StubbedThing()
    let tested = ObjectUnderTest()
    objectUnderTest.thing = stubbed
    let result = tested.doSomethingThatEventuallyCallsMethodBeingStubbed()
    XCTAssertTrue(result == "A Known String!")
    }

    View Slide

  33. Mocking Network Responses

    View Slide

  34. ¡¡ Flagrant
    plug alert !!

    View Slide

  35. VOKMockUrlProtocol for iOS
    Mocktrofit for Android
    open-source projects of Vokal, my employers

    View Slide

  36. View Slide

  37. HTTP/1.1 200 OK
    Server: nginx/1.4.6 (Ubuntu)
    Date: Wed, 12 Nov 2014 22:10:40 GMT
    Content-Type: application/json
    Transfer-Encoding: chunked
    Connection: keep-alive
    Vary: Accept
    X-Frame-Options: SAMEORIGIN
    Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
    {
    "default": true,
    "expiration_month": "10",
    "expiration_year": "2018",
    "last_4": "1234",
    "card_type": "MasterCard",
    "id": 2
    }

    View Slide

  38. {
    "default": true,
    "expiration_month": "10",
    "expiration_year": "2018",
    "last_4": "1234",
    "card_type": "MasterCard",
    "id": 2
    }

    View Slide

  39. #import "VOKMockURLProtocol.h"
    @implementation CLTAPIClient (MockData)
    - (void)setShouldUseMockData:(BOOL)shouldUseMockData
    {
    Class mockURLProtocol = [VOKMockUrlProtocol class];
    NSMutableArray *currentProtocolClasses =
    [self.sessionConfiguration.protocolClasses mutableCopy];
    if (shouldUseMockData) {
    [currentProtocolClasses insertObject:mockURLProtocol atIndex:0];
    } else {
    [currentProtocolClasses removeObject:mockURLProtocol];
    }
    self.sessionConfiguration.protocolClasses = currentProtocolClasses;
    }
    @end

    View Slide

  40. Test your networking logic
    and your UI against
    known data

    View Slide

  41. Test networking logic with
    a live server

    View Slide

  42. Know what you can
    depend on

    View Slide

  43. Sometimes this can cause a
    big fight

    View Slide

  44. You are at the mercy
    of your internet connection

    View Slide

  45. Testing against a live server
    can change things

    View Slide

  46. Testing against a live server
    can return different data
    if someone else changed something

    View Slide

  47. Know the limits
    of what you can test live

    View Slide

  48. Don't lock yourself out

    View Slide

  49. Test that you're getting
    expected response types,
    not exact data

    View Slide

  50. Test the things that
    aren't already covered

    View Slide

  51. Code Coverage tools

    View Slide

  52. Local code coverage

    View Slide

  53. View Slide

  54. View Slide

  55. View Slide

  56. View Slide

  57. Remote code coverage
    Designed to work with
    Continuous Integration
    servers
    » codecov.io
    » coveralls.io

    View Slide

  58. "I must cover every
    single line of code"

    View Slide

  59. The most useless test I ever inherited:
    [Note: class prefixes have been changed to
    protect the guilty]

    View Slide

  60. Don't let the perfect
    be the enemy
    of the good

    View Slide

  61. focus on why something
    needs to be covered rather
    than whether it's covered

    View Slide

  62. How
    do you write tests?

    View Slide

  63. Test
    Driven
    Developlment

    View Slide

  64. You have seen
    The TDD demo
    (and it has usually taken way too long)

    View Slide

  65. The TL;DR version
    of the TDD demo

    View Slide

  66. 1. Write a failing test
    LargerTest.m
    Larger.m

    View Slide

  67. 1. Write a failing test
    LargerTest.m
    Larger.m

    View Slide

  68. 2. Write code to make it pass
    LargerTest.m
    Larger.m

    View Slide

  69. 2. Write code to make it pass
    LargerTest.m
    Larger.m

    View Slide

  70. 3-∞. Refactor, but now
    with the guardrails of the test
    LargerTest.m
    Larger.m

    View Slide

  71. 3-∞. Refactor, but now
    with the guardrails of the test
    LargerTest.m
    Larger.m

    View Slide

  72. Repeat for every
    public method you write.

    View Slide

  73. Behavior
    Driven
    Development

    View Slide

  74. Same idea as TDD
    Different approach

    View Slide

  75. Does it do what it's supposed to
    for the end user?

    View Slide

  76. Given / When / Then

    View Slide

  77. You can use libraries
    to enforce BDD
    Kiwi
    Specta
    Cedar

    View Slide

  78. View Slide

  79. I personally prefer
    to use XCTest
    for non-UI tests

    View Slide

  80. [ Demo: BDD in pure XCTest ]

    View Slide

  81. BDD Demo Recap:
    » Use very descriptive test names.
    » Test the end result, not necessarily how you got
    there.
    » Use the XCTest methods you already know.
    » Use comments if you need the structure of given/
    when/then.

    View Slide

  82. UI Testing

    View Slide

  83. A word about
    XCUI Testing

    View Slide

  84. KIF

    View Slide

  85. Keep
    It
    Functional

    View Slide

  86. Kif Pros
    » Write your UI tests in
    Objective C!
    » Uses Accessibility, so you
    make your app accessible in
    the bargain
    » Get to the bit you need to
    test
    » The most widely used
    library
    » Very backwards compatible

    View Slide

  87. Kif Cons
    » Slow (can be sped up now!)
    » Can be flaky on CI servers
    » Some folks have had issues
    with lookup changing the
    view hierarchy
    » Very backwards compatible

    View Slide

  88. [ Demo: Kif In Action ]

    View Slide

  89. Testing your UI
    en muchos idiomas
    !"#$%&'()

    View Slide

  90. View Slide

  91. !

    View Slide

  92. View Slide

  93. View Slide

  94. UI Testing Recap
    » If you're swapping out your app delegate for
    tests, make sure you put it back for UI tests
    » Centralize your localized strings in a convenience
    class to make strings easier to test
    » UI and non-UI tests should be separate targets
    » Add -AppleLanguages "\(en\)" arguments to the test
    bit of your application's scheme
    » Duplicate your scheme and update for every
    language you support

    View Slide

  95. A Final word of
    warning

    View Slide

  96. Tests do not
    and cannot
    catch everything

    View Slide

  97. Tests catch
    mistakes in the rosy path and
    known bad states

    View Slide

  98. Humans
    use your application

    View Slide

  99. Humans are weird

    View Slide

  100. Humans multitask

    View Slide

  101. Humans and Robots
    working together
    to break your app
    make your app better

    View Slide

  102. Official Summary Slide™
    » Testing lets you refactor confidently
    » Testing helps you find out immediately when you
    broke something so it's easier to fix.
    » Test as much as you can, however much that is.
    » Find the testing ideology that works best for you.
    » UI Testing can give you a great opportunity to see
    how all the pieces of your app work together.
    » Have both humans and robots test your app.

    View Slide

  103. Questions?

    View Slide

  104. Things from me or my former employer!
    #humblebrag
    » https://github.com/designatednerd/
    TestingPlayground
    » https://github.com/designatednerd/FlickrSearcher
    » https://github.com/designatednerd/
    DNSiOSLocalizationTestHelpers
    » https://github.com/vokal/VOKMockUrlProtocol
    » https://github.com/vokal/Mocktrofit

    View Slide

  105. Mocking tools!
    » http://ocmock.org/
    » https://github.com/jonreid/OCMockito
    UI Testing Tools!
    » https://github.com/kif-framework/KIF
    » https://github.com/Raizlabs/FRY

    View Slide

  106. Code Coverage Tools!
    » https://codecov.io/
    » https://coveralls.io
    » https://github.com/jonreid/XcodeCoverage
    » https://github.com/dropbox/XCoverage
    » http://www.xcoverageapp.com/

    View Slide

  107. BDD Tools!
    » https://github.com/specta/specta
    » https://github.com/kiwi-bdd/Kiwi
    » https://github.com/pivotal/cedar
    Other Things I Mentioned!
    » http://ntoll.org/article/tdd-cargo-cult
    » http://qualitycoding.org/app-delegate-for-tests/

    View Slide

  108. Photo Credits
    » Angry mob by Robert Course-Baker: https://
    www.flickr.com/photos/[email protected]/3645211083
    » Robot by Logan Ingalls: https://www.flickr.com/
    photos/plutor/847695350
    » Lock ("Hodgepodged") by David Goehring https://
    www.flickr.com/photos/carbonnyc/4740626368/
    » All images of Kif from Futurama used without
    permission. Sorry, Fox.

    View Slide