The decision
A useful test protects a behavior that matters: unpaid users cannot download a paid file, invalid input cannot create an account, or a retry does not create two deliveries. Tests that merely repeat the implementation’s internal steps can pass while the product is broken. Start from the consequence of failure and choose the smallest test that can catch it.
A worked example
For a digital purchase, one unit test checks payment-status parsing. An integration test sends two valid webhook events concurrently and checks the database. A browser check confirms that a customer can find the download button and that a failed verification page does not announce a successful payment. Each test covers a different risk.
How to put it into practice
- Write the expected outcome before selecting a test framework.
- Use realistic fixtures for boundary cases, including missing data and stale events.
- Mock the external boundary rather than the whole business operation when testing database behavior.
- Keep production credentials and real card charges out of automated tests. Use isolated data and provider sandbox objects.
A failure to plan for
A test that mocks both the database insert and the function that calls it proves very little about durability. Keep the transaction and constraints real when the failure mode involves concurrency or persistence.
Try it on your project
Pick one operation from your app. Describe a normal case, an invalid case, a retry, and a dependency failure. For each, write what the person sees and what durable state should exist afterward.
Keep the next step small
Use the free demand scorecard or planning tools to make your assumptions explicit. The $19 launch kit brings the blueprint and seven editable worksheets together.