如何用 AI 编写软件测试:实用指南
学习如何用 AI 编写软件测试、选择有价值的测试用例、审查生成的代码并执行可靠的检查,而不是盲目信任每一条建议。
Key takeaways
- Give AI the intended behavior, relevant code, and testing conventions—not just a request to “write tests.”
- Review expected results yourself. Generated tests can repeat the same mistakes as the implementation.
- Run tests in a safe environment, check that they catch deliberate bugs, and keep useful tests in your normal workflow.
AI can help a developer draft software tests, identify edge cases, and explain failures. But a convincing test is not necessarily a correct one.
The most reliable approach is to treat AI as a drafting partner. You define what the code should do, ask for focused tests, then verify that those tests detect real problems.
What you need
Before starting, gather:
- A small piece of code: One function, endpoint, or component is enough.
- Its requirements: Describe correct behavior, including errors and boundary conditions.
- Your existing testing setup: Include the language, framework, test command, and one representative test.
- An approved AI assistant: Check your organization’s policy before sharing source code.
- A safe execution environment: Use a local test environment or isolated sandbox without production credentials.
Remove secrets, customer information, and sensitive logs from anything you share. Prefer synthetic test data over copies of production records.
Step by step
1. Define the behavior before sharing the implementation
Start with a plain-English specification. Without one, AI may simply turn the current implementation—including its bugs—into expected results.
For example:
`shipping_fee(subtotal_cents)` accepts a nonnegative integer subtotal in cents. Shipping costs 500 cents below 5,000 cents and is free at or above 5,000 cents. Negative subtotals raise `ValueError`.
This gives you independently checkable outcomes. It also avoids ambiguity about currency units and the free-shipping threshold.
If requirements are unclear, ask the assistant to list questions before writing tests. Do not let it silently invent behavior for unsupported inputs.
2. Give the AI a focused testing brief
Provide the function, its specification, and a nearby test that shows your project’s conventions. Include relevant dependencies, but avoid uploading the entire repository unnecessarily.
Use a prompt like:
Write unit tests for the function below using Python’s built-in `unittest`. Follow the supplied specification and existing test style. First list the cases you recommend and any unclear requirements. Do not change production code or add dependencies. Keep tests deterministic and explain what each case verifies.
For other projects, replace the language and framework with your existing setup.
Separating test planning from code generation makes incorrect assumptions easier to catch.
3. Review the proposed cases
Ask for a short case list before accepting generated code. Look for:
- Normal behavior: A typical valid input.
- Boundaries: Values just below, at, and above a threshold.
- Failure behavior: Invalid inputs or dependency failures covered by the requirements.
- Regression cases: Inputs that previously caused a bug.
For the shipping example, useful subtotals include 0, 4,999, 5,000, and 5,001 cents, plus a negative value.
Choose the right testing level. Unit tests check small pieces of logic. Integration tests check interactions, such as database queries. End-to-end tests check complete user workflows.
Do not ask AI to cover every level at once. Start with the smallest useful scope.
4. Generate a small, readable test file
Ask the assistant to implement the approved cases. Keep the first batch small enough to inspect line by line.
Assuming the function lives in `shipping.py`, a draft might look like this:
```python
import unittest
from shipping import shipping_fee
class ShippingFeeTests(unittest.TestCase):
def test_shipping_fee_boundaries(self):
cases = [
(0, 500),
(4999, 500),
(5000, 0),
(5001, 0),
]
for subtotal, expected in cases:
with self.subTest(subtotal=subtotal):
self.assertEqual(
shipping_fee(subtotal),
expected,
)
def test_negative_subtotal_is_rejected(self):
with self.assertRaises(ValueError):
shipping_fee(-1)
if __name__ == "__main__":
unittest.main()
```
Notice that the expected values come from the specification. The tests do not recreate the shipping calculation to derive their answers.
Check imports, function signatures, fixtures, and assertions. AI can reference helpers or methods that do not exist in your project.
5. Run the tests and investigate failures
For the example above, save the file as `test_shipping.py` and run this from the project directory:
```bash
python -m unittest test_shipping.py
```
Use your project’s established command for other setups.
Review generated code before execution, especially if it installs packages, accesses files, or makes network calls. A passing test run should not require production access.
When something fails, classify the problem:
- Does the test misunderstand the requirement?
- Is the setup or import incorrect?
- Does the implementation contain a bug?
Share the relevant failure output with the assistant after removing sensitive information. Ask it to explain the cause before suggesting changes. Never accept “fixes” that merely weaken assertions to make tests pass.
6. Check whether the tests catch a bug
Passing tests alone do not prove that the tests are useful.
Temporarily introduce a small, deliberate defect in a local working copy. For example, change the free-shipping condition from “at or above 5,000” to “above 5,000.”
The test for exactly 5,000 cents should fail. If it does not, investigate the test or whether it is running at all. Revert the deliberate defect afterward.
This is a simple form of mutation testing: checking whether tests notice incorrect behavior.
7. Add reviewed tests to your normal workflow
Once the tests are trustworthy, commit them with the relevant code and run them in continuous integration.
Keep tests repeatable. Control time and randomness where necessary, and isolate external services when testing local logic. Use separate integration tests to verify real interactions.
When AI suggests additional cases, prioritize business risk and known bugs. More generated tests are not automatically better tests.
Common mistakes
- Treating implementation as the specification: This can preserve existing defects.
- Checking only that code runs: Assert meaningful outputs, state changes, or required errors.
- Mocking everything: Excessive mocking can hide broken interactions.
- Chasing coverage alone: Executed lines may still lack useful assertions.
- Accepting automatic rewrites: Review changes to both production code and tests.
- Leaving flaky tests unresolved: Uncontrolled timing, networks, and shared state undermine trust.
Tools that help
- [Claude](/tools/claude): Useful for discussing requirements, drafting test cases, and reviewing failure output. Verify its suggestions in your project.
- [Amazon Q Developer](/tools/amazon-q-developer): An option for AI-assisted coding alongside security scanning and transformation capabilities. Review generated test code before adopting it.
- [Buddy AI Sandboxes](/tools/buddy-ai-sandboxes): Provides isolated cloud environments for running and testing code written by AI agents.
- [Mintlify](/tools/mintlify): Helps draft and maintain developer documentation. Clear behavioral documentation can provide better context for testing prompts.
FAQ
Can AI write tests for existing code?
Yes. Provide the relevant code, intended behavior, and existing test conventions. For undocumented behavior, distinguish between preserving current behavior and confirming that it is correct.
Should AI-generated tests replace manual testing?
No. They can support automated checks, but exploratory testing and human review still matter, especially for usability, unclear requirements, and unexpected workflows.
How do I know whether an AI-generated test is good?
It checks a clear requirement, produces repeatable results, and fails when that behavior breaks. You should be able to explain its expected result without relying on the AI’s explanation.