Testing
Unit tests, pytest, mocks, and linters.
6 questions
JuniorTheoryVery commonWhat is mocking in tests?
What is mocking in tests?
Replacing a real dependency (network, disk, DB, external service) with a fake stand-in that mimics its interface, so a test stays isolated, fast, and deterministic. unittest.mock (Mock/patch) provides this.
Common mistakes
- ✗Asserting on the mock's own behavior instead of the code under test
- ✗Patching the wrong import path so the real dependency still runs
Follow-up questions
- →What is the difference between a mock, a stub, and a fake?
- →Why must you
patchwhere a name is looked up, not where it is defined?
JuniorTheoryCommonWhich tools check Python code style and quality?
Which tools check Python code style and quality?
Linters and formatters like pycodestyle/flake8 (PEP 8 checks), pylint (style plus logic), black (auto-formatter), and mypy (static type checks) catch style issues and some error classes before runtime.
Common mistakes
- ✗Treating a clean
pylint/mypyrun as proof the logic is correct, so no behavioral tests are written - ✗Assuming
mypychecks runtime behavior rather than only the static type annotations
Follow-up questions
- →How do
blackandflake8differ in what they enforce? - →Why is
mypycomplementary to a runtime test suite, not a replacement?
JuniorTheoryCommonWhat is the test pyramid?
What is the test pyramid?
A model for the test mix: many fast, isolated unit tests at the base, fewer integration tests in the middle, and few slow end-to-end tests on top. It pushes coverage toward cheap, fast tests.
Common mistakes
- ✗Inverting the pyramid by relying mostly on slow end-to-end tests
- ✗Reading it as a ranking of importance rather than of quantity and speed
Follow-up questions
- →Why are unit tests preferred at the base over end-to-end tests?
- →What is the 'testing trophy' and how does it differ from the pyramid?
MiddleTheoryCommonHow do unit and integration tests differ?
How do unit and integration tests differ?
A unit test exercises one isolated unit with its dependencies mocked — fast, pinpointing failures. An integration test checks that several units, or a unit plus a real DB or API, work together, catching wiring problems units miss.
Common mistakes
- ✗Calling a test 'unit' while it still hits a real database or network
- ✗Assuming integration tests should mock every dependency like unit tests do
Follow-up questions
- →Where do end-to-end tests sit relative to these two?
- →Why do unit tests localize a failure better than integration tests?
MiddleTheoryOccasionalHow do you test a function that calls a flaky external service?
How do you test a function that calls a flaky external service?
Don't hit the real network in a unit test. Inject the client as a dependency, or patch it, and substitute a mock returning controlled responses — timeouts and error codes included — so you deterministically test each branch.
Common mistakes
- ✗Letting a unit test make a real network call to the flaky service
- ✗Mocking only the happy path and never asserting the timeout and error-code branches
Follow-up questions
- →How would you simulate a timeout versus an HTTP 500 with a mock?
- →Where would a real integration test against this service still belong?
SeniorTheoryOccasionalWhen do you prefer dependency injection over patch-style mocking?
When do you prefer dependency injection over patch-style mocking?
Prefer injection when you control the design: passing collaborators in makes substitution explicit and refactor-safe. patch reaches into a module to replace names — handy for legacy code, but brittle to import paths.
Common mistakes
- ✗Treating injection and mocking as mutually exclusive rather than complementary
- ✗Assuming
patchtargets survive a module move or rename unchanged
Follow-up questions
- →How does constructor injection improve testability over module-level globals?
- →When is
patchthe only practical option for legacy code?