Skip to main content


Testing features, not code

Test-Driven Development

  • Canon TDD β€’ β€œWrite a list of the test scenarios you want to cover. Turn exactly one item on the list into an actual, concrete, runnable test. Change the code to make the test (& all previous tests) pass (adding items to the list as you discover them). Optionally refactor to improve the implementation design.” β€’ Kent Beck πŸ“–
  • TDD for those who don’t need it β€’ Funny talk showing how to use TDD to loop through a declarative list of requirements you list up front β€’ Chew Choon Keat πŸ“Ί
  • TDD, Where Did It All Go Wrong? β€’ How to apply TDD as originally intended and avoid bad practices like testing implementation details instead of required behaviours β€’ Ian Cooper πŸ“Ί
  • TDD: The Bad Parts β€’ Identifies bad testing practices to avoid and includes tips like pairing tests with behaviours, not files β€’ Matt Parker πŸ“Ί
  • Five Underplayed Premises Of TDD | Video β€’ GeePaw Hill πŸ“–
  • TDD β€’ Questions whether TDD leads to building the right thing when you first need to explore a problem before deciding how to solve it β€’ The Primeagen πŸ“Ί


Testing in production

API Testing

Model-based testing


  • unit testing made easier by refactoring all functions to be pure (even if some inputs never change while the app runs):

    • pure functions are easier to test than functions that read values from the environment (e.g. variables defined outside the function as env vars, top-level file vars, etc)
    • but sometimes some of those input values won’t actually change from one call to the next (e.g. config values that remain the same during the life of the app process that are read in middleware functions that run before/after each request to that app)
    • for unit testing purposes, it’s nice if all those used values are passed as inputs that can be easily faked
    • however for performance purposes, it may be costly to recompute the same values each time the function is called
    • option 1: read values defined at file level inside the function, stop passing them in as args, and mock those global values in the test
      • can require very annoying mocking boilerplate depending on which test framework you’re using and where those values are coming from
    • option 2: continue passing those values as args, but make them optional args with their default values set to those file-level definitions
      • benefits: compute those default values once + app itself never passes those optional args (simpler function calls) + test gets to override those optional args with whatever fake values are useful for simulating changes in the config/env, etc
    • got this idea from MH in this helpful PR review thread
  • Unlighthouse - open source tool to run Lighthouse on every page on a site in seconds with one command