Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Common Challenges & Best Practices for TDD on iOS

1,142 views

Published on

Presented at the June 2016 Tokyo iOS Meetup on 6/11/2016, in this presentation I give an overview of test driven development and how it can be used when developing for iOS / Swift.

TDD is an enormous topic so this really just scratches the surface to give an expansive glimpse into the journey that TDD truly is. Those unfamiliar with TDD will hopefully have a desire to learn more about it while those familiar will hopefully learn something new.

Published in: Software
  • Be the first to comment

Common Challenges & Best Practices for TDD on iOS

  1. 1. TEST DRIVEN DEVELOPMENT COMMON CHALLENGES & 
 BEST PRACTICES FOR Tokyo iOS Meetup June 2016Derek Lee @derekleerock ON IOS
  2. 2. COMMON PITFALLS & BEST PRACTICES FOR TDD YOUR PRESENTER Tokyo iOS Meetup June 2016Derek Lee @derekleerock 4/2015~11/2015 12/2015~ 1/2014~
  3. 3. WHY TDD? Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  4. 4. T D D Tokyo iOS Meetup June 2016Derek Lee @derekleerock Question What is TDD?
  5. 5. TEST DRIVEN DEVELOPMENTTokyo iOS Meetup June 2016Derek Lee @derekleerock Question What is TDD?
  6. 6. Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  7. 7. WRITE A TEST MAKE IT PASS YADDA YADDA YADDA Tokyo iOS Meetup June 2016Derek Lee @derekleerock Challenge Getting over the hump
  8. 8. TDD CRASH COURSE Tokyo iOS Meetup June 2016Derek Lee @derekleerock Challenge Getting over the hump
  9. 9. TESTING WORKFLOW: RED → GREEN → REFACTOR ▸ Write a failing test ▸ Write the simplest implementation to make it pass ▸ Refactor ▸ Repeat Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  10. 10. ▸ Compiler Errors = Failing Test Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP TESTING WORKFLOW: RED → GREEN → REFACTOR
  11. 11. ▸ Red = Failing Test Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP TESTING WORKFLOW: RED → GREEN → REFACTOR
  12. 12. ▸ Green = Passing Test Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP TESTING WORKFLOW: RED → GREEN → REFACTOR
  13. 13. TESTING WORKFLOW: RED → GREEN → REFACTOR ▸ Keyboard Shortcuts for improving your test workflow: ▸ ⌘ + 5 → Show the Xcode Test Navigator ▸ ⇧ + ⌘ + U → Compile Tests ▸ ⌘ + U → Run All Tests In Suite ▸ MAGIC + U → Run all tests for current class ▸ MAGIC + G → Re-run last test * MAGIC = ⌃ + ⌥ + ⌘ Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  14. 14. WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT ▸ Setup - Create objects needed to execute the test ▸ Action - Prod the subject (object) under test ▸ Verify - Make assertions about your expectations Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  15. 15. WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT ▸ Override setUp() and tearDown() methods as needed Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  16. 16. WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT ▸ Clearly indicate where the “Act” portion of your test is: Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  17. 17. ▸ Use the appropriate assertion for your test expectation (XCTest) Tokyo iOS Meetup June 2016Derek Lee @derekleerock let number = 11 XCTAssertTrue(number == 12) error: -[MyProjectTests.MyObjectTest testMethod] : XCTAssertTrue failed - GETTING OVER THE HUMP WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT
  18. 18. ▸ Use the appropriate assertion for your test expectation (XCTest) Tokyo iOS Meetup June 2016Derek Lee @derekleerock let number = 11 XCTAssertEqual(number, 12) error: -[MyProjectTests.MyObjectTest testMethod] : XCTAssertEqual failed: ("Optional(11)") is not equal to ("Optional(12)") - GETTING OVER THE HUMP WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT
  19. 19. ▸ XCT Assertion Types ▸ AssertTrue, AssertFalse ▸ AssertEqual, AssertNotEqual (+WithAccuracy) ▸ AssertLessThan, AssertGreaterThan (+OrEqual) ▸ AssertNil, AssertNotNil ▸ AssertThrowsError Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT
  20. 20. ▸ Nimble (Matcher Framework) ▸ expect(~).to(~) or expect(~).toNot(~) ▸ expect(~).to(beTrue()) or expect(~).to(beFalse()) ▸ expect(~).to(beLessThan(~)) // greaterThan… ▸ expect(~).to(beAKindOf(~)) ▸ Can also write custom matchers with Nimble Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP WRITING TESTS TDD STYLE: ARRANGE → ACT → ASSERT
  21. 21. GOLDEN RULES OF TDD ▸ Test First ▸ Simplest Solution ▸ Test Once ▸ Test in Isolation ▸ Test the interface, not the implementation Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  22. 22. TDD BEST PRACTICES ▸ One Failing Test at a Time ▸ Create a Test List ▸ Assert First ▸ Simplest Test Data / Evident Test Data ▸ Avoid conditionals and loops Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  23. 23. CLASSIC ▸ “Detroit” or “Chicago” ▸ Prefers real objects ▸ Focus: Algorithms ▸ State verification ▸ Test doubles as needed Tokyo iOS Meetup June 2016Derek Lee @derekleerock MOCKIST ▸ “London” ▸ Prefers mocks ▸ Focus: Object Interactions ▸ Behavior verification ▸ Test doubles always GETTING OVER THE HUMP
  24. 24. CONTINUOUS INTEGRATION ▸ Build and test in a clean environment ▸ Automation of your test suite ▸ Test across OSs, simulators, devices ▸ Xcode Server, TeamCity, Travis, CircleCI, Jenkins… Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  25. 25. CONTINUOUS INTEGRATION - XCODE SERVER BIG SCREEN Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  26. 26. CONTINUOUS INTEGRATION - PIVOTAL PROJECT MONITOR Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  27. 27. TAKING THE BLUE PILL ▸ BDD ▸ Clean Architecture ▸ SOLID Principles: SRP, Open/Closed, LSP, ISP, DIP ▸ Don’t Repeat Yourself ▸ Just In Time Design ▸ Refactoring ▸ Continuous Integration Tokyo iOS Meetup June 2016Derek Lee @derekleerock GETTING OVER THE HUMP
  28. 28. MY TESTS TAKE FOREVER TO RUN Tokyo iOS Meetup June 2016Derek Lee @derekleerock Challenge The Time-Consuming Test Run
  29. 29. THE TIME-CONSUMING TEST RUN THE USUAL SUSPECTS ▸ Imbalanced Test Suite ▸ Testing Against External Resources Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  30. 30. TESTING ICE-CREAM CONE ANTI-PATTERN Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  31. 31. TESTING ICE-CREAM CONE ANTI-PATTERN Tokyo iOS Meetup June 2016Derek Lee @derekleerock ▸ Brittle ▸ Expensive to write/maintain ▸ Time consuming to run UI & MANUAL TESTS CAN BE…
  32. 32. TESTING PYRAMID Tokyo iOS Meetup June 2016Derek Lee @derekleerock ] ] ARE WE BUILDING THE RIGHT SYSTEM? ARE WE BUILDING THE SYSTEM RIGHT?
  33. 33. TESTING PYRAMID Tokyo iOS Meetup June 2016Derek Lee @derekleerock TIMETOTESTINCREASES
  34. 34. THE TIME-CONSUMING TEST RUN DESIRED TEST SUITE QUALITIES FOR QUICK TEST FEEDBACK ▸ Few ▸ Fast ▸ Stable ▸ Thorough Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  35. 35. THE TIME-CONSUMING TEST RUN WHEN TO RUN TESTS ▸ Current Unit/Feature → While building an object / feature ▸ All Units + All Feature → Before commit / push; after pulling updates from a repo; ▸ Integration, UI → CI Suite ▸ Manual → As needed Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  36. 36. THE TIME-CONSUMING TEST RUN WHEN TO RUN TESTS ▸ Create a target for each suite of tests that you want to run Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  37. 37. THE TIME-CONSUMING TEST RUN WHEN TO RUN TESTS ▸ Configure scheme(s) to execute tests: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  38. 38. THE TIME-CONSUMING TEST RUN WHEN TO RUN TESTS ▸ Use a makefile with xcodebuild (or xctool) to execute the tests when you need to or from CI: Tokyo iOS Meetup June 2016Derek Lee @derekleerock units: @xcodebuild -project Osusume.xcodeproj -scheme "Osusume" -sdk iphonesimulator -destination "platform=iOS Simulator,OS=9.3,name= iPhone 6" build test integration: @xcodebuild -project Osusume.xcodeproj -scheme "Osusume-Staging" -sdk iphonesimulator -destination "platform=iOS Simulator,OS=9.3, name=iPhone 6" build test
  39. 39. THE TIME-CONSUMING TEST RUN GUIDANCE ON UNIT TESTING - HOW/WHAT TO TEST ▸ Sandi Metz Rails Conf 2013 “The Magic Tricks of Testing” Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  40. 40. THE TIME-CONSUMING TEST RUN DO MY TESTS HIT EXTERNAL DEPENDENCIES? ▸ Network, REST APIs ▸ Database (includes Core Data!) ▸ File System ▸ External Library or API Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  41. 41. THE TIME-CONSUMING TEST RUN THEN HOW TO TEST EXTERNAL DEPENDENCIES? ▸ Find the seams where communication occurs ▸ Confirm expected interactions using mock objects ▸ Create an integration test if needed Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  42. 42. THE TIME-CONSUMING TEST RUN GUIDANCE ON MOCK OBJECTS ▸ Martin Fowler, “Mocks Aren’t Stubs” http://martinfowler.com/articles/mocksArentStubs.html ▸ Uncle Bob, “The Little Mocker” Blog Post https://blog.8thlight.com/uncle-bob/2014/05/14/ TheLittleMocker.html Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  43. 43. MY TEST SUITE FEELS UNSTABLE Tokyo iOS Meetup June 2016Derek Lee @derekleerock Challenge The Brittle Test Suite
  44. 44. THE BRITTLE TEST SUITE THE USUAL SUSPECTS ▸ Highly-coupled objects ▸ Long, complicated, or unreadable tests Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  45. 45. THE BRITTLE TEST SUITE HIGHLY COUPLED OBJECTS - DESIGN & ARCHITECTURE ▸ TDD encourages us to write loosely coupled components that can be easily tested in isolation and combined later. ▸ May need to revisit your architecture ▸ “Build & Swap” ▸ Too difficult or too costly to refactor? ▸ TDD a new component and swap it in Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  46. 46. THE BRITTLE TEST SUITE BUILD & SWAP EXAMPLE #1 - DRUM APP NAVIGATION UX Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  47. 47. THE BRITTLE TEST SUITE BUILD & SWAP EXAMPLE #2 - MIKADO REFACTOR Tokyo iOS Meetup June 2016Derek Lee @derekleerock ▸ Parse Integration Before: ▸ One single “God” object singleton: ParseHelper.h/.m ▸ Included in 25 other classes ▸ Parse Integration After: ▸ 4 Dependency-Injected Testable “Repository” objects ▸ Can move each repository over as needed
  48. 48. THE BRITTLE TEST SUITE HOW TDD HELPS ▸ Design ▸ Loosely coupled objects ▸ Well thought out public object APIs ▸ Dev ▸ Gives immediate feedback on quality ▸ Refactoring confidence Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  49. 49. THE BRITTLE TEST SUITE HOW TO APPROACH ▸ Practice, practice, practice ▸ Reference Materials ▸ Read “Refactoring: Improving the Design of Existing Code” (Martin Fowler) ▸ Read “Working Effectively With Legacy Code” (Michael Feathers) Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  50. 50. I DON’T KNOW HOW TO TEST X Tokyo iOS Meetup June 2016Derek Lee @derekleerock Challenge Fear of the Unknown
  51. 51. FEAR OF THE UNKNOWN THE USUAL SUSPECTS ▸ What to test - what not to test ▸ How to test specific objects, dependencies, scenarios Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  52. 52. FEAR OF THE UNKNOWN KNOWING WHAT NOT TO TEST ▸ Private Methods (this is an implementation detail!) ▸ UI Design (fonts, colors, positions, constraints) ▸ Configuration Details (supporting data) ▸ Auto-generated code ▸ Test Fixtures, Test Doubles ▸ Reference: https://blog.8thlight.com/uncle-bob/ 2014/04/30/When-tdd-does-not-work.html Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  53. 53. FEAR OF THE UNKNOWN HOW TO TEST… VIEW CONTROLLERS ▸ Move logic out of MegaController (*Andy Matuschak - https://realm.io/news/andy-matuschak-refactor-mega- controller/) ▸ Using Storyboards: ▸ Property Dependency Injection ▸ Without Storyboards: ▸ Constructor Dependency Injection Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  54. 54. FEAR OF THE UNKNOWN HOW TO TEST… CORE DATA ▸ Use an in-memory Core Data Store ▸ Only setup data needed for test Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  55. 55. FEAR OF THE UNKNOWN HOW TO TEST… UITABLEVIEW / UICOLLECTIONVIEW ▸ Extract Datasource and/or Delegate to external object for easier testing ▸ Leverage blocks / closures for common logic Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  56. 56. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Swift: Mocks in Swift via Protocols (Blog post, Eli Perkins) http://blog.eliperkins.me/mocks-in-swift-via-protocols Tokyo iOS Meetup June 2016Derek Lee @derekleerock For Objective-C, see OCMock
  57. 57. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Find the method definition(s) on the object that you need to confirm interactions with: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  58. 58. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Create your own protocol definition to duplicate the method you want to confirm interaction with: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  59. 59. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Create a fake object (spy) that implements that protocol: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  60. 60. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Write your test: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  61. 61. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Write the implementation: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  62. 62. FEAR OF THE UNKNOWN HOW TO TEST… NSUSERDEFAULTS ▸ Pass in the real object for production code: Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  63. 63. EASY TO FALL BACK TO OLD HABITS Tokyo iOS Meetup June 2016Derek Lee @derekleerock Challenge Commitment
  64. 64. COMMITMENT THE USUAL SUSPECTS ▸ Frustration, Fatigue ▸ Cutting corners ▸ Falling back to what is most comfortable ▸ Test last or not testing at all Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  65. 65. TOOLS YOU’LL NEED ▸ Focus ▸ Patience ▸ Tenacity ▸ Discipline ▸ Dedication Tokyo iOS Meetup June 2016Derek Lee @derekleerock COMMITMENT
  66. 66. TIME MANAGEMENT HOW TO APPROACH ▸ Start Small ▸ 1% each day ▸ Think long-term: Investing in the future of your software Tokyo iOS Meetup June 2016Derek Lee @derekleerock
  67. 67. REWARDS OF STICKING TO IT ▸ Making forward progress in small increments ▸ Allows refactoring to take place with confidence ▸ Identify bugs early and avoid regressions ▸ Reduces costs up-front ▸ Add new features knowing you won’t break existing ones ▸ Deploy anytime with confidence ▸ Easier to understand code for you and your team Tokyo iOS Meetup June 2016Derek Lee @derekleerock COMMITMENT
  68. 68. @DEREKLEEROCK Thank you! Tokyo iOS Meetup June 2016Derek Lee @derekleerock

×