How Do You Write Testable Requirements for Software-Intensive Hardware Systems?
A requirement that cannot be verified is not a requirement. It is a statement of intent, and statements of intent do not close anomalies, satisfy certification audits, or prevent late-cycle rework. For software-intensive hardware systems — embedded controllers, sensor fusion platforms, autonomous subsystems, anything where firmware and silicon are jointly responsible for behavior — the gap between “written” and “testable” is wide, and the consequences of not closing it are measured in schedule months.
This guide covers the structural qualities that make requirements testable, the specific ways software-adjacent requirements fail those qualities, and the verification methods available beyond traditional test campaigns. It also addresses when in the development process these problems can be caught most cheaply.
What Makes a Requirement Testable
Three properties are necessary. All three must be present simultaneously.
1. Quantifiable Acceptance Criteria
A testable requirement specifies a threshold that either passes or fails. Not a range of subjective adequacy — a boundary. “The system shall respond within 50 milliseconds” is a threshold. “The system shall respond quickly” is not. “The unit shall operate at temperatures between -40°C and +85°C” is a threshold. “The unit shall operate in harsh environments” is not.
The acceptance criterion must be stated in units that a measurement instrument or analysis procedure can produce. Time, voltage, current, frequency, bit error rate, data throughput, probability of detection, probability of false alarm — these are acceptable. “User-friendly,” “robust,” “efficient,” and “adequate” are not.
For software-intensive systems, this rule applies to software-observable quantities too. Latency, CPU utilization ceiling, interrupt response time, memory allocation limits, state machine transition conditions — all of these can be made quantifiable. The requirement author’s job is to find the number, not to defer it.
2. Defined Conditions
A verifiable requirement specifies the conditions under which the stated behavior must hold. Without conditions, you cannot construct a test case — you don’t know what to set up.
Conditions include: input stimulus range, operating mode, interface state, environmental context (temperature, vibration, EMI), hardware configuration version, and any preconditions the system must be in before the requirement applies. For software-intensive systems, the operating mode clause is especially important. A processor that must achieve 95% throughput “during normal operation” means something entirely different depending on whether the interrupt load, DMA contention, and cache state are specified.
Defined conditions also mean defined exclusions. If the requirement applies only in a specific fault mode, say so. If it does not apply during initialization, say so. Ambiguity in scope is one of the most common sources of test escapes.
3. Single-Subject Statements
Each requirement shall address exactly one verifiable property of exactly one system element. Compound requirements — those containing “and” or “or” connecting two distinct obligations — cannot be given a single pass/fail verdict. If one clause passes and the other fails, what is the requirement status? Undefined.
The practical fix is mechanical: split every compound requirement at the conjunction. Write two requirements. Assign each a unique identifier. Allocate each to the system element responsible. This feels bureaucratic until the first test campaign, at which point it becomes obviously necessary.
Single-subject also means single system element. A requirement that says “the processor and the FPGA shall together maintain data integrity” cannot be allocated to either element’s test suite without ambiguity. The processor team will assume the FPGA owns it; the FPGA team will assume the processor does. Interface requirements are real and necessary — but they must name the interface, not both sides of it simultaneously.
How Software-Adjacent Requirements Fail These Criteria
Software-intensive hardware systems produce a specific and recurring set of requirement pathologies. Recognizing them on first read is a learnable skill.
Behaviors That Are Hard to Observe
Software state is often internal. A requirement like “the firmware shall correctly manage the transmit buffer during high-load conditions” describes an internal behavior with no specified external observation method. “Correctly” is undefined. “High-load” is undefined. The transmit buffer state is not directly observable from the system interface.
The fix is to push the requirement to an observable output. What external signal, data packet, timing measurement, or fault indicator changes when the transmit buffer is managed incorrectly? Write the requirement in terms of that observable. If there is no observable external manifestation of a behavior, either add an observability mechanism (a diagnostic register, a test point, a logged health counter) or reconsider whether the requirement belongs at the system level.
Performance That Depends on Environment
Latency, throughput, and power consumption in embedded systems are functions of input load, thermal state, clock configuration, and silicon revision. A requirement that states “the ADC shall complete a 16-bit conversion in under 2 microseconds” is incomplete without specifying the clock frequency at which that applies, the operating voltage range, and the ambient temperature. At a different temperature or with a different clock configuration, the same silicon may fail the requirement while behaving exactly as designed.
Environmental dependencies must be declared in the conditions clause, not assumed. If the requirement applies across a range of environmental conditions, the worst-case condition for the stated criterion must be identified and explicitly included. “Shall achieve X under all conditions within the operating envelope” is an acceptable formulation — it commits the designer to worst-case analysis and commits the test team to environmental testing.
Emergent Properties
Some system behaviors genuinely emerge from the interaction of software and hardware components rather than residing in any single element. System-level latency through a DSP pipeline, end-to-end fault detection time, or data integrity across a multi-node bus — these properties are real and must be verified. The problem is that they are often written as if they can be verified by component-level testing of individual elements.
Emergent properties require integration-level or system-level verification. The requirement must be allocated to the correct indenture level — not to a component that cannot demonstrate it alone. When an emergent property is incorrectly allocated to a component, the component test team either finds it unverifiable (correctly) or writes a marginal test that demonstrates the property in an unrepresentative environment (incorrectly and expensively).
The additional complication is that emergent properties are frequently discovered during test, not during requirements authoring. When a test team says “we can’t write a test for this,” the correct response is not to skip the test — it is to trace the problem back to the requirement and fix the requirement’s indenture level, conditions, or observability before proceeding.
Verification Methods Beyond Testing
Testing — executing the system with defined inputs in a defined environment and measuring outputs against acceptance criteria — is the most familiar verification method. It is not always the most appropriate one.
Analysis
Analysis applies analytical procedures, models, or simulations to predict whether a requirement will be met without physically stimulating the production article. It is appropriate when:
- The requirement specifies a behavior under conditions that are impractical or unsafe to induce physically (destructive stress, radiation environments, fault injection at high voltage)
- The requirement addresses a statistical property that would require prohibitively large test sample sizes to verify empirically
- The requirement concerns internal states that are not externally observable without analysis of timing diagrams, power models, or behavioral simulations
Analysis produces a prediction, not a measurement. The verification artifact is a documented analysis procedure with stated assumptions, accepted by program authority. When a requirement is closed by analysis, the assumptions must be recorded — they become inputs to risk reviews.
Inspection
Inspection verifies a requirement by examining the artifact directly — reading the code, reviewing the schematic, checking the bill of materials, examining the drawing. It is appropriate when:
- The requirement specifies a constraint on implementation rather than on behavior (shall use a specific communication protocol, shall not use dynamic memory allocation, shall be implemented in a specific programming language)
- The requirement addresses a design property that is definitionally true if implemented correctly and cannot be meaningfully distinguished by behavioral test
- Compliance with a standard or process requirement is being verified
Inspection cannot verify behavior. It can verify that the design, as documented, conforms to the stated constraint. Inspection closure requires a defined checklist or review procedure and an identified reviewer — not an informal walkthrough.
Demonstration
Demonstration verifies a requirement by operating the system in front of an observer, without formal instrumented measurement. It is appropriate when:
- The acceptance criterion is a qualitative operational capability (“the display shall show the current operating mode in all lighting conditions”)
- The behavior is either clearly present or clearly absent, without needing instrumentation to determine which
- A formal test setup would add cost and delay without adding confidence
Demonstration is frequently underused in software-intensive hardware programs because it feels informal. It is not informal — it requires a defined procedure, defined pass criteria (even if qualitative), and a signed acceptance record. For software-intensive systems, demonstration is the right method for human-interface requirements, accessibility requirements, and operational workflow requirements that cannot be reduced to a measurement without doing violence to what they actually mean.
Catching Problems Before Test Planning
The traditional failure mode is this: requirements are written during system definition, reviewed in a requirements review meeting where no one has the bandwidth to scrutinize testability, and handed to the test team six months later. The test team discovers the untestable requirements during test plan authoring and opens a requirements change request. The change request cycles through systems engineering, goes to the customer for approval, and comes back with a test planning impact. The schedule moves right.
The intervention point is requirements authoring, not test planning. Testability assessment during authoring — before the requirement baseline is signed — costs almost nothing compared to the same assessment after contract baseline or CDR.
This is where modern AI tooling changes the economics. Flow Engineering’s requirements platform includes AI-assisted testability assessment that operates at authoring time. When a requirement is written or imported, the system flags structural problems: missing quantification, absent conditions, compound statements, vague qualitative terms, internal-only behaviors with no observation path. It suggests specific corrected language — not generic guidance, but restructured text that preserves the design intent while making the criterion measurable. A systems engineer can work through a requirement set of several hundred items in a fraction of the time a manual review would take, and the AI flags precisely the failure modes described in this article.
This matters most for software-intensive requirements, where the failure modes are subtle. “The bootloader shall complete initialization before the application begins executing” sounds specific, but it has no timing criterion and no definition of what “complete initialization” means externally. Flow Engineering’s AI will identify both gaps and suggest adding a measurable time bound and a defined external signal — a GPIO, a CAN message, a logged timestamp — that makes the requirement observable.
The AI’s suggestions are not final answers. They are structured prompts that force the requirement author to make a decision they would otherwise defer. The decision is recorded in the requirement, not in someone’s memory.
Practical Starting Points
Before writing a requirement, ask: what instrument or procedure would I use to determine pass or fail? If you cannot answer, write the observable output first and derive the requirement statement from it.
When reviewing a requirement, apply the three-criteria check mechanically: Is there a quantified threshold? Are the conditions defined? Does the statement address exactly one property of one element? If any answer is no, mark it for rework before the review ends.
When allocating requirements, identify whether each requirement is a component property or a system-level emergent property. Requirements that require more than one element to jointly demonstrate should be allocated to an integration verification event, not to a component test.
When choosing a verification method, default to test only when a behavioral measurement is both necessary and feasible. Ask explicitly whether analysis, inspection, or demonstration would be more appropriate before committing to a test case that may not be executable.
When setting up a requirements tool, configure it to flag unverifiable requirements at entry — not at review. The earlier the flag appears, the cheaper the fix.
The quality of a requirement set is visible long before test. The engineers who will eventually build the test plan can read a requirement and know immediately whether it was written by someone who thought through verification or someone who did not. Writing testable requirements is a technical discipline, and like all technical disciplines, it rewards the systematic application of specific principles over general good intentions.