Practices
Testing practices under question: tests first, testing in production, manual testing, flaky tests and types.
Most asked
- Is unit testing worth it?Yes
- Should I use TDD?Code under test: Yes
- Should I mock all dependencies in unit tests?Code under test: Yes
- Should developers write their own tests?Code under test: Yes
- Should I use mocks in unit tests?Code under test: Yes
Yes18
- Do doctests replace unit tests?
No, doctests replace unit tests only for the examples a reader needs: keep two or three doctests that show the main path, run them in CI with `pytest --doctest-modules`, and write the edge cases and error branches as pytest tests.
Code under test: Yes
- Is it unprofessional not to write tests?
Yes, shipping code that customers use without tests is unprofessional when a failure would show as a plausible wrong value: write a test for each rule the change adds, in the same pull request, and run the suite in CI.
Code under test: Yes
- Is unit testing necessary in web development?
Yes, unit testing is necessary in web development for the rules that decide a result, such as form validation, deadlines and status changes: one unit test per branch and boundary, run in CI on every pull request.
Code under test: Yes
Yes, unit testing is worth it for the rules in your code that decide a result, such as status changes, date rules and validation: one test per branch and boundary, run in CI on every pull request.
Yes, beginners should write unit tests for code that other people use, from their first task on a team: one test for each rule and boundary the change adds, with the expected value worked out by hand, run in CI on every pull request.
- Should code review come before testing?
No, automated tests come before code review: write them in the same pull request, let CI pass before a reviewer starts, have the reviewer read the tests with the code, and run any manual check last, on the approved commit.
Code under test: Yes
- Should developers write their own tests?
Yes, the developer who changes the code writes its unit and integration tests in the same pull request, with expected values taken from the ticket, and the reviewer checks those cases against the ticket, not against the code.
Code under test: Yes
Yes, change business logic whose design blocks a test: pass the clock, the database rows and outside services in as parameters or constructor arguments, make no other change, and test the logic in CI.
- Should I commit failing tests?
Yes, commit a test that reproduces a known bug, marked as an expected failure with the issue number (pytest xfail with strict=True, Vitest test.fails, Jest test.failing), so the build on main stays green and the run fails on the day a change fixes the bug.
Code under test: Yes
- Should I mock all dependencies in unit tests?
No, do not mock all dependencies in unit tests: replace only what leaves the process or changes between runs, such as HTTP APIs, email, the database and the clock, and test the unit with your own in-process classes running for real.
Code under test: Yes
Yes, run a short read-only smoke test against production after each deploy, with one test account that analytics, email and billing skip, and roll back when it fails; keep the full end-to-end suite in CI.
- Should I use BDD?
Yes, use BDD for rules that customers see: agree on concrete examples with the product owner before coding, automate each example as a test through the API in CI, and add Cucumber's Gherkin files only when someone who does not write code reads them.
Code under test: Yes
- Should I use mocks in unit tests?
Yes, use mocks in unit tests for collaborators that leave the process or give a different answer on each run, such as another team's service, an email provider or the clock; use real objects for your own code, in-memory fakes for your own repositories, and assert on results instead of calls.
Code under test: Yes
- Should I use TDD?
Yes, use TDD for business rules and calculations whose correct result you can state before you write the code: write one failing test from the requirement, write the code that makes it pass, refactor, and keep the tests in CI.
Code under test: Yes
Yes, before fixing a typical bug, write a test with the input from the report, run it on the unfixed code, and see it fail for the reason the report describes.
- Should I write tests before code?
Yes, write the test before the code whenever you can state the expected result in advance, such as a rule from a ticket or the input from a bug report, and see the test fail before you write the code.
Code under test: Yes
Yes, write tests before you refactor code that has none: characterization tests at the code's entry point that record what it returns today for each branch, run in CI after every refactoring step.
Yes, write tests for code you proved correct by hand: one test per case of the proof and one per assumption it makes, such as sorted input or a sum that fits in an int, because the proof covers only the code as it was when you proved it.
No2
No, not every test should be automated: a manual check of a stable read-only screen whose failures users report costs more to automate than the failures it prevents, so look at that screen by hand when a release changes it, and automate a check once it covers money, access, saved data or a flow that changes monthly.
Do not write tests that repeat a rule your type checker or linter enforces on every merge, such as argument types or a missing null check; spend the tests on the values the code computes.