Effective testing: how to confidently deploy on a Friday

Effective testing: how to confidently deploy on a Friday

Have you ever worked on a codebase that had a high test coverage, yet regularly had bugs slip into production? This can
lower our confidence in our tests, and make us question why we even bother with them. In this talk, we'll cover how to
write tests that get us the most value and confidence for the least effort.

63328f785a094cd8ae71939b8f70773f?s=128

Mohamed Oun

October 23, 2019
Tweet

Transcript

  1. 1.

    Effective testing Mohamed3on How to write tests that let you

    confidently deploy on a Friday By Mohamed Oun Software Engineer at HelloFresh mohamed3on.online
  2. 4.

    We write tests to give us more confidence The point

    of tests is NOT to tell you that you made changes, it’s to tell you whether your changes broke something
  3. 5.

    If we want developers to embrace a culture of testing,

    we have to show the benefits to it
  4. 6.

    Tests should serve as a documentation for how the code

    works • Think about clear names for your test cases • Be explicit about what you’re testing • Avoid DRY test code, It’s ok to duplicate test objects and code to make clearer, easier to read test cases
  5. 8.

    Tests should be as flexible and accommodating as possible Think

    hard of the core functionalities you don’t want to break, and focus on testing those
  6. 10.

    Two ways to test for this • Ensure that all

    recipe cards are 170px height (current default size) • Ensure that all recipe cards have the same height (more flexibility)
  7. 11.

    Fix your bugs by writing tests for them 1. Find

    out the buggy function that’s returning a wrong value for some inputs (easier said than done). 2. call the function with those inputs in a test. 3. Use that test to reproduce the bug and fix it. Why? 1. Rerunning that test is much faster that reproducing manually over and over. • Faster feedback loop leads to faster bug fixes 2. Having that test in the test suite ensures this bug never happens again
  8. 12.

    How do I know if my test is bad? •

    If your test broke when your source code didn’t, it’s a bad test • If your source code broke when your test didn’t, it’s a bad test
  9. 14.

    What shouldn’t break your tests • Adding a data-test-id •

    Refactoring without changing functionality • Changing styles* (fonts, colours, paddings) * unless it’s a reusable UI component (example: Design System)
  10. 16.
  11. 17.
  12. 18.

    Avoid snapshots as much as you can • They’re implicit,

    so it’s hard to know exactly what the test is for • They’re usually brittle, breaking when the component’s functionality doesn’t • They almost always fail the (bad test) test • Can be helpful in the case of reusable UI components (ex. design system components)
  13. 19.

    Many of your unit tests can be replaced by a

    type system* *Not sponsored by Microsoft
  14. 20.
  15. 21.

    VS

  16. 22.

    100% test coverage is a trap “When a measure becomes

    a target, it ceases to be a good measure.”
  17. 23.

    High test coverage is NOT an indicator that your tests

    are sufficient • Focusing on high test coverage leads to low-quality, easy-gain tests (hint: snapshots) • you get diminishing returns on your tests as the coverage increases much beyond 70-80% • Very high coverage means that you are likely testing implementation details, which means your tests will probably break while refactoring, ironically making it harder, not easier, to refactor your code.
  18. 24.

    OK, so how do I know if my test suite

    is good enough? • You rarely get bugs that escape into production. • You are rarely hesitant to change some code for fear it will cause production bugs.
  19. 27.

    React components have 2 main users The developer using the

    component in another component, and the user seeing the rendered output
  20. 28.

    • Clicking on an interactive element (end user) • Changing

    props for a component (developer user) • Instead of testing component state/methods, testing the rendered output Black box testing in UI
  21. 30.
  22. 32.

    How do I know if I’m testing implementation details? •

    Imagine you didn’t have access to the source code of what you are testing, would you still be able to write that test?
  23. 34.

    How to know if my test is unit, integration or

    E2E? • If you mock everything, it’s a unit test • If you mock nothing, it’s an end to end test • Everything in between is an integration test
  24. 36.

    Unit → integration → E2E 1. Amount of code tested

    2. Confidence 3. Testing implementation details Trade-offs
  25. 37.
  26. 38.

    Testing tools • Cypress/Selenium: • Integration ↔ E2E • Run

    in a real browser • Can still mock API responses • Jest: Enzyme/React-testing-library: Unit ↔ Integration • Run in an emulated browser • Can mock almost everything (functions, components, API responses)
  27. 41.

    Summary • Prefer explicit over implicit tests (avoid snapshots in

    most cases). • Use tests to fix the bugs you find • Use test coverage as a guide, not as a goal. • Prefer integration tests to get the most confidence and value out of your tests (mock as few things as possible). • Write tests that mimic real world usage of your application, and avoid testing implementation details (black-box testing). • Use a type system if you can.