How to Write a Hardware Test Plan with TofuPilot
A hardware test plan defines what gets tested, at which stage, with what equipment, and against which criteria. Without one, test coverage depends on whoever wrote the last script. This guide walks through structuring a test plan from EVT through production and implementing it in Python with TofuPilot.
What a Test Plan Covers
| Section | Content |
|---|---|
| Product overview | What the product does, key specifications |
| Test stages | Which tests run at EVT, DVT, PVT, production |
| Test procedures | Step-by-step instructions per test |
| Equipment list | Instruments, fixtures, software |
| Pass/fail criteria | Measurement limits per test |
| Data requirements | What gets recorded, where, retention period |
| Roles | Who writes tests, who runs them, who reviews results |
The test plan is a living document. It starts rough in EVT and gets refined through each build stage.
Step 1: Map Requirements to Test Stages
Start with the product requirements and decide when each one gets verified.
| Requirement | EVT | DVT | PVT | Production |
|---|---|---|---|---|
| Output voltage within 5% | X | X | X | X |
| Survives 1m drop | X | |||
| Operates -20C to 60C | X | X | ||
| Firmware boots in under 2s | X | X | X | X |
| Leakage current below 500uA | X | X | ||
| FPY above 95% | X | X |
Not every requirement needs testing at every stage. EVT focuses on basic functionality. DVT covers environmental and stress. PVT validates the manufacturing process. Production tests run on every unit.
Step 2: Define Test Procedures
Each test procedure becomes an OpenHTF test script. Define the measurements and limits directly in code so the test plan and the implementation stay in sync.
import openhtf as htf
from openhtf.util import units
@htf.measures(
htf.Measurement("output_voltage_V")
.in_range(minimum=4.75, maximum=5.25)
.with_units(units.VOLT),
htf.Measurement("boot_time_ms")
.in_range(maximum=2000)
.with_units(units.MILLISECOND),
htf.Measurement("leakage_current_uA")
.in_range(maximum=500)
.with_units(units.MICROAMPERE),
)
def phase_production_checks(test):
"""Production test: voltage, boot time, safety."""
test.measurements.output_voltage_V = 5.02
test.measurements.boot_time_ms = 1350
test.measurements.leakage_current_uA = 85.0Step 3: Specify Equipment and Fixtures
Document every instrument in the test plan. This prevents "it works on my bench" problems.
| Instrument | Model | Purpose | Calibration |
|---|---|---|---|
| DMM | Keysight 34461A | Voltage and current | Annual |
| Power supply | Rigol DP832 | DUT power | Annual |
| Fixture | Custom PCB jig v2.1 | Pogo pin contact | Per shift check |
| PC | Any, Python 3.10+ | Test execution | N/A |
Step 4: Set Initial Limits
Start with limits from the datasheet or design spec. Tighten them after DVT data shows the actual distribution.
import openhtf as htf
from openhtf.util import units
# EVT: wide limits, learning the design
evT_voltage = htf.Measurement("voltage_V").in_range(
minimum=4.5, maximum=5.5
).with_units(units.VOLT)
# DVT: tightened based on EVT data
dvt_voltage = htf.Measurement("voltage_V").in_range(
minimum=4.7, maximum=5.3,
marginal_minimum=4.75, marginal_maximum=5.25,
).with_units(units.VOLT)
# Production: final limits with margins
prod_voltage = htf.Measurement("voltage_V").in_range(
minimum=4.75, maximum=5.25,
marginal_minimum=4.8, marginal_maximum=5.2,
).with_units(units.VOLT)Step 5: Connect to TofuPilot
Log every test run to TofuPilot from the start. EVT data informs DVT limits. DVT data informs production limits. This only works if the data is captured consistently.
from tofupilot.openhtf import TofuPilot
test = htf.Test(phase_production_checks)
with TofuPilot(test):
test.execute(test_start=lambda: input("Scan serial: "))TofuPilot tracks results across all test stages. Open the Analytics tab to see measurement distributions, yield trends, and failure patterns. This data feeds back into the test plan as you refine limits and add or remove test steps.
Common Mistakes
| Mistake | Fix |
|---|---|
| Testing everything at every stage | Map requirements to specific stages |
| Limits from the datasheet only | Refine from actual production data |
| Test plan in a Word doc, code elsewhere | Define limits in code, keep them in sync |
| No calibration tracking | Log instrument info with each run |
| Skipping EVT data collection | Start logging from the first prototype |
A test plan is not a one-time document. Review it after every build stage and update limits, procedures, and equipment based on what the data shows.