A Python service calculates discounts differently for loyalty customers, trial users and refunded orders. A developer asks Copilot to “write tests for this module.” The assistant generates clean-looking examples that all exercise ordinary successful purchases. Every test passes, but the refunded-order bug remains. Generated tests can accelerate coverage, yet their value depends on whether they assert independently defined behavior and probe the paths likely to fail.
The GH-300 developer productivity and testing objectives include unit and integration tests, edge cases, assertions, and security improvements. This makes testing a reasoning task: decide which boundary is important, give the assistant sufficient context, and verify that the new test would catch a meaningful regression rather than merely execute lines. A high coverage percentage alone cannot establish correctness.
Start from the contract, not the implementation
Write expected outcomes for the discount service before providing the function body. Describe valid users, invalid inputs, currency precision, refund rules, and the interaction with database state. If the test oracle is copied entirely from the current implementation, a defect can become a permanent expectation. An independent specification lets generated cases challenge the code instead of flattering it.
For a refunded order, state that no discount may increase the amount returned beyond the original payment. A useful test includes a negative amount, a duplicate refund request, and an expired promotion. These cases represent business meaning, not arbitrary numeric extremes.
Use boundary values that exercise real branches
Copilot can propose zero, minimum, maximum, null, empty list, Unicode, duplicate records and invalid authorization cases. Choose values based on actual constraints. A maximum integer test may be less useful than a price with three decimal places when rounding is the danger. For asynchronous code, a duplicate delivery or late acknowledgment may be more revealing than an ordinary repeated call.
Ask the assistant to explain which invariant each case protects. If a test has no clear purpose or cannot fail under a realistic defect, either improve it or omit it. Test suites create maintenance cost; a thousand weak cases can obscure a handful of important regressions.
Separate unit tests from integration and contract tests
A unit test can prove local discount calculations with mocked dependencies. It cannot establish that the API serializes the correct currency value, the database commits atomically, or an external payment provider honors an idempotency key. Use integration or contract tests for boundaries where the outcome depends on a real implementation or protocol agreement.
For database access, a mocked repository can hide transaction isolation bugs. For HTTP clients, a simulated response can hide authentication header mistakes or unexpected retries. Decide which dependency needs a real test environment and which can be safely substituted. The web application testing fundamentals offer a complementary view of testing authorization and input-handling boundaries rather than only happy-path functionality.
Verify test code is not a disguised tautology
An assistant may generate an assertion that checks whether its own function returned any number, or mock away the exact dependency under test. Such a case raises coverage while failing to protect behavior. Inspect inputs and expected values independently. Deliberately introduce a small mutation in a nonproduction branch—such as reversing one comparison—to confirm the regression test fails.
Mutation-based thinking is especially useful for generated tests. If changing > to >= does not fail a supposed boundary test, the case may not be exercising the intended limit. Avoid keeping a brittle mutation framework solely for appearances, but use occasional deliberate faults to validate the suite’s ability to detect mistakes.
Test authorization and confidentiality explicitly
Generated code often interacts with credentials, logs and customer records. Add tests that prove users cannot read another tenant's object, a rejected input does not reveal a secret, and errors preserve only the safe details needed for support. Do not use real access tokens in test fixtures. A fake secret-like marker is enough to verify that logs and responses do not leak sensitive fields.
An automated test can detect one known violation but cannot prove the absence of every vulnerability. Pair security-focused tests with review, static scanning, dependency monitoring and appropriate threat modeling. The Copilot code-review article addresses how independent review checks a change even when test output is green.
Generate data that resembles failure conditions
Synthetic data helps exercise high-cardinality tenants, long names, non-ASCII text, out-of-order events and unusual transaction paths. Ask for deterministic seeds and small representative datasets before creating millions of random rows. Test values should be valid or intentionally invalid according to the specification and should not contain production personal data.
For a refund workflow, include a duplicate message arriving after the first payment reversal succeeded. A test that only retries before the first success misses the most dangerous condition. Sample data is valuable when it represents the failure mode, not when it simply makes test output large.
Maintain a trustworthy test-fix loop
When a generated test fails, determine whether the code is wrong, the test expectation is wrong, or the environment differs from the assumptions. Do not automatically ask the assistant to “make tests pass,” because it may weaken assertions or delete difficult cases. Preserve the intended behavior as a separate statement and require changes to be justified against it.
Run the suite with the project’s real command and supported version. Record the actual return status and any skipped tests. If an integration test cannot run without credentials, mark it unverified rather than claiming it passed. GH-300’s practical advantage is faster test discovery and scaffolding while preserving independent evidence of correctness.