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

Justin Crown - "WHAT IS THIS MESS?" - Writing tests for pre-existing code bases

Justin Crown - "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!

https://us.pycon.org/2018/schedule/presentation/88/

PyCon 2018

May 11, 2018
Tweet

More Decks by PyCon 2018

Other Decks in Programming

Transcript

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

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

    IT? If it has... do YOU want to break it?
  3. 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
  4. Why SHOULDN’T We? I’m Lazy LAZY means being too lazy

    to fight fires, not being too lazy to write a test
  5. 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
  6. Choose Thy Weapons • Find a test runner that works

    for you • Use pre-existing tools for your framework/modules • Create reusable test scaffolding
  7. 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
  8. Assignment 1 Feature Request (alter existing functionality) Update “Quark” model

    to conditionally determine the value of the “magic” property
  9. Assignment 1 Unit Test • Should cover the smallest piece

    of code possible • Should run fast • Should not use a database, file I/O, etc.
  10. Assignment 1 Where Did We Go Wrong? We should test

    the FUNCTIONALITY of legacy applications (integration testing)
  11. Assignment 2 Dealing With Code That Touches The World Fixing

    a bug in a method that has side effects
  12. 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
  13. 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
  14. 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)
  15. 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
  16. 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 code even worse
  17. 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
  18. 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
  19. 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
  20. Create A Legacy Start testing things you don’t need to

    test Test Sprints Keep Testing! Brain refreshment