What Is This Mess? (Writing Tests For Pre-Existing Code Bases)

What Is This Mess? (Writing Tests For Pre-Existing Code Bases)

Many of us practice test driven development, and pride ourselves in our code coverage. This is relatively easy to do when you begin a new project, but what happens when you take over an existing code base with little to no tests? Where and how do you start writing tests? This task can be very intimidating and frustrating, but can be accomplished!

This talk will run through some common approaches and methodologies for adding test coverage to pre-existing code (that you might not even be familiar with at all). The next time you take over an untested monolith, you will be able to do the right thing and start writing tests instead of hoping for the best!

8c67512f4b6b2137fa70111e66ceb76a?s=128

Justin Crown

May 11, 2018
Tweet

Transcript

  1. WHAT IS THIS MESS? (Writing tests for pre-existing code bases)

  2. Justin Crown https://github.com/mrname/ WOW!

  3. None
  4. What Is Legacy Code? • Lacking Tests • Lacking Documentation

    • Difficult to read or reason about
  5. Why Should We Write Tests For Legacy Code?

  6. Why SHOULDN’T We? It will be replaced eventually NO IT

    WON’T (maybe it will... but not right now)
  7. Why SHOULDN’T We? It has been working just fine HAS

    IT? If it has... do YOU want to break it?
  8. Why SHOULDN’T We?

  9. Why SHOULDN’T We? I do not have time It takes

    more time (and money) to debug issues in the wild It will take less time (and money) to work with in the future
  10. Why SHOULDN’T We? I’m Lazy LAZY means being too lazy

    to fight fires, not being too lazy to write a test
  11. Why Do I Have To Be The One To Start?

  12. Why Do I Have To Be The One To Start?

  13. None
  14. None
  15. Test What You Touch • Write a test that asserts

    current behavior... BEFORE YOU TOUCH CODE • Write a test that asserts new/modified behavior. LET IF FAIL • Do code stuffs • Tests pass • Profit Significantly
  16. None
  17. Choose Thy Weapons • Find a test runner that works

    for you • Use pre-existing tools for your framework/modules • Create reusable test scaffolding
  18. Choose Thy Weapons • pytest for test runner • pytest-django

    - utilities for django integration • pytest-socket - disable socket JUST IN CASE • pytest-cov - code coverage reports • factory_boy - avoid boilerplate when creating model instances
  19. Choose Thy Weapons Requirements File

  20. Choose Thy Weapons Test Runner Configuration

  21. Assignment 1 Feature Request (alter existing functionality) Update “Quark” model

    to conditionally determine the value of the “magic” property
  22. Assignment 1 New VIP Client! Master Of Quarks

  23. Assignment 1

  24. Assignment 1

  25. Assignment 1 Scaffolding - tests/model_factory.py

  26. Assignment 1 Unit Test • Should cover the smallest piece

    of code possible • Should run fast • Should not use a database, file I/O, etc.
  27. Assignment 1 Unit Test (Test Class)

  28. Assignment 1 Unit Test (Test Existing Functionality)

  29. Assignment 1 Unit Test (Test Existing Functionality)

  30. Assignment 1 Unit Test (Test NEW Functionality)

  31. Assignment 1 Unit Test (Test NEW Functionality)

  32. Assignment 1 Unit Test (Test NEW Functionality)

  33. Assignment 1 Unit Test (Test NEW Functionality)

  34. None
  35. Assignment 1 There is a Problem Still...... WAT

  36. Assignment 1 Where Did We Go Wrong? We should test

    the FUNCTIONALITY of legacy applications (integration testing)
  37. Assignment 1

  38. Assignment 1 Integration Test

  39. Assignment 1 WHYYYYYYYYYY

  40. Assignment 2

  41. Assignment 2 Dealing With Code That Touches The World Fixing

    a bug in a method that has side effects
  42. Assignment 2 Give It An Array Of Integers

  43. Assignment 2 Get Back a New Array With Crazy Sauce

    On Top
  44. Assignment 2 Let’s Read the Code But Don’t Touch

  45. Assignment 2 Let’s Read the Code But Don’t Touch

  46. Assignment 2 Where to Start? Let’s just try to get

    the class in a test harness
  47. Assignment 2

  48. Breaking Dependencies

  49. Assignment 2 Subclassing

  50. Assignment 2 Subclassing

  51. Assignment 2 Let’s Test Out The View

  52. Assignment 2 Let’s Test Out The View

  53. Assignment 2 Mocking

  54. Assignment 2 Mocking

  55. Assignment 2 Make The World A Better Place

  56. Assignment 2 Fix Things

  57. Assignment 2 Hold Up Now

  58. Assignment 2 We could have broken things using that mutated

    argument
  59. Assignment 2

  60. Assignment 2 Backs Against The Wall

  61. Assignment 2 Sometimes it makes sense to change code to

    make it more testable But ONLY if we can do that without breaking the interface And preferably only if it makes ACTUAL sense
  62. Assignment 2 Sometimes it makes sense to change code to

    make it more testable But ONLY if we can do that without breaking the interface And preferably only if it makes ACTUAL sense
  63. Assignment 3 Adding New Features To Existing (and Unruly) Things

  64. Assignment 3 Adding New Features To Existing (and Unruly) Things

  65. Assignment 3 Assignment - Add extra reporting (SMS)

  66. Assignment 3 I want the full thing under test before

    I start
  67. Assignment 3 Mock Our Way Through It?

  68. Assignment 3 Mock Our Way Through It! Advantages • Existing

    code is fully tested without changing anything Disadvantages • Difficult to implement (tons of mocks for a single test) • Tests are brittle (tied to the implementation itself)
  69. Assignment 3 Refactor?

  70. Assignment 3 Refactor?

  71. Assignment 3 Refactor? Advantages • Code is easier to read

    and work with • Code is easier to test Disadvantages • Might break something • Not directly required to implement feature
  72. Assignment 3 I have no time but need to add

    the thing
  73. Assignment 3 Just Write The Code In The Existing Method

    Advantages • Quickest way to get the job done Disadvantages • Code is untested • Highly likely to break something • You just made the world more terrible
  74. Assignment 3 Make a New Method. Call It From The

    Old One
  75. Assignment 3 Make a New Method. Call It From The

    Old One Advantages • We can write a small piece of code that we can test Disadvantages • We cannot test the way the calling method uses our code
  76. Assignment 3 Subclass

  77. Assignment 3 Subclass Advantages • We can add functionality without

    affecting existing class • Tests are better, because we can mock super() to test the way they work together Disadvantages • Increased complexity of code base • Must replace existing class instances with new one
  78. Are We Making Progress? Using Code Coverage Reports

  79. Are We Making Progress Using Code Coverage Reports

  80. Are We Making Progress Using Code Coverage Reports

  81. Are We Making Progress Using Code Coverage Reports

  82. Create A Legacy (the good kind)

  83. Create A Legacy Pushing code should run a build that

    runs tests Builds should fail if tests fail CI/CD Builds should fail if test coverage drops
  84. Create A Legacy Start testing things you don’t need to

    test Test Sprints Keep Testing! Brain refreshment
  85. Afterthoughts

  86. None