Testing & Validation · Study deck

Unit Testing for IoT Firmware

Picture a temperature rule that passes every normal value but fails after a device update.

Test Tessa is your guide for this deck.

firmware-testingunit-testshardware-seams
Test Tessa, the module guide, in a scene from this chapter.
iotclass.org

After studying this chapter

Learning objectives

You will be able to:

  • use seams and test doubles to isolate hardware-dependent code
  • build a reviewable unit-test record
  • explain why a green unit suite can still lie about system behavior
  • Explain: A unit test checks one small piece of firmware logic on its own, with controlled inputs and a result you can read.
iotclass.org

Major section

Overview: Checking One Small Behavior in Isolation

A unit test checks one small piece of firmware logic on its own, with controlled inputs and a result you can read.

  • The word that does the work is isolation.
  • You can confirm the gear has the right number of teeth and turns smoothly in your hand long before the clock exists.

Key terms

Unit tests
Unit tests are the per-gear checks of firmware.

Why it matters

Those elements make the run fast and repeatable because the sensor, clock, bus, or radio is represented rather than physically present.

A unit test draws a boundary: controlled input and a test double on one side, an assertion on the behavior, and an explicit note of what it leaves open.
A unit test draws a boundary: controlled input and a test double on one side, an assertion on the behavior, and an explicit note of what it leaves open.
iotclass.org

Major section

Overview: Checking One Small Behavior in Isolation (continued)

If you only need the intuition, this layer is enough: a unit test isolates one firmware behavior, feeds it controlled inputs, and checks a reviewable result.

  • That check is fast and certain, but it does not tell you the assembled clock keeps time — that needs the other gears, the spring, and the case.
  • Unit tests are the per-gear checks of firmware.
  • This boundary keeps a green unit result both valuable and honest.
iotclass.org

Major section

Overview: Checking One Small Behavior in Isolation (continued)

A parser that turns a byte sequence into a reading can be fed a malformed sequence to confirm it rejects it instead of crashing.

  • Fast and repeatable Because it avoids real hardware and timing, it runs in milliseconds and gives the same result every run, so it can run on every commit.
  • Proves logic, not the device A pass confirms the logic given the test's inputs; the real sensor, bus, and timing still need integration and hardware-aware evidence.
  • If you can explain isolation and what a pass does and does not claim, you have the core idea.
iotclass.org

Major section

Practitioner: Seams, Test Doubles, and a Reviewable Record

Firmware is hard to unit-test when logic is welded directly to hardware — reading a register inline, calling a vendor driver, or sleeping on a real timer.

  • Most firmware unit tests need only stubs and fakes to supply inputs and a couple of spies or mocks to confirm an output call happened.

Key terms

No warning
No warning is raised.
Boundary values
Boundary values are where off-by-one logic breaks.
Proves the unit
Proves the unit is isolated and repeatable.
A unit-test record ties each result to the behavior under test, the boundary it drew, what it asserted, what it left open, and the change that reopens it.
A unit-test record ties each result to the behavior under test, the boundary it drew, what it asserted, what it left open, and the change that reopens it.
iotclass.org

Major section

Practitioner: Seams, Test Doubles, and a Reviewable Record (continued)

Worked Example: A Sensor Threshold Decision Consider firmware that takes a sensor reading and decides whether to raise a warning.

  • Those fields admit what mocks, stubs, and isolated code cannot prove and identify the change that invalidates the result.
  • No warning is raised.
  • Confirms the common path does not false-alarm.
iotclass.org

Major section

Practitioner: Seams, Test Doubles, and a Reviewable Record (continued)

The record connects a fast green test to the wider testing pyramid without overstating it as system validation.

  • The test then asserts the verdict and, where it matters, that a diagnostic was recorded.
  • Stub returns a value one step above the limit.
  • A warning is raised exactly at the boundary.
iotclass.org

Major section

Practitioner: Seams, Test Doubles, and a Reviewable Record (continued)

If you can place a seam, pick the right double, and write a record that names what stays open, you can stop here.

  • Boundary values are where off-by-one logic breaks.
  • The reading is rejected, not treated as real.
  • Bad sensor data must not become a false decision.
iotclass.org

Major section

Under the Hood: Why a Green Unit Suite Can Still Lie

Coverage Counts Lines, Not Cases A coverage percentage tells you which lines executed, not whether the cases that matter were tried.

  • Unit tests fail to protect firmware in three recurring ways: the test double does not match real behavior, the tests are over-coupled to implementation, and coverage is mistaken for quality.
  • A fake flash never wears out or fails a write; real flash does.
  • Sensor, driver, or data-shape change.

Why it matters

The unit test passes because the logic is correct against the double, yet the device fails because the double never reproduced the messy reality.

iotclass.org

Major section

Under the Hood: Why a Green Unit Suite Can Still Lie (continued)

A Double Is Only as Good as Its Fidelity The deepest trap in firmware unit testing is the stand-in that lies.

  • A stub returns a clean reading instantly; the real sensor returns a noisy value after a settling delay, or a status byte the firmware must check first.
  • Determinism Is Engineered, Not Assumed "Repeatable" does not happen by accident.
  • Behavior may be wrong while calls still match.
iotclass.org

Major section

Under the Hood: Why a Green Unit Suite Can Still Lie (continued)

The usual sources of flakiness in firmware tests are real time and delays, randomness, uninitialized or shared global state, and order dependence between tests.

  • Over-Mocking Makes Brittle, Low-Value Tests Verifying a result (state) is usually more robust than verifying the exact sequence of internal calls (interaction).
  • When a test asserts every internal call, it breaks on a harmless refactor that did not change behavior, and it can pass even when the behavior is wrong as long as the calls match.
  • Asserting implementation instead of behavior.: Over-mocked tests break on refactors and miss real bugs.
iotclass.org

Major section

Under the Hood: Why a Green Unit Suite Can Still Lie (continued)

Tolerating flakiness.: An intermittent unit-test failure is a defect, not a rerun candidate.

  • Prefer asserting the observable outcome — the returned value, the resulting state, or the one output call that matters — and reserve strict call-order mocks for the few cases where the sequence is the behavior.
  • The fixes are concrete: inject a controllable clock instead of sleeping, seed or stub randomness, reset state in setup, and never let one test rely on another having run first.
  • Reading coverage as quality.: Lines executed is not cases tried; design the cases that break things.
iotclass.org

Major section

Under the Hood: Why a Green Unit Suite Can Still Lie (continued)

A test that fails once in fifty runs is not noise to rerun; it is a defect in the test or the code.

  • A suite can run most of a parser on well-formed input and report a high number while never feeding it the malformed packet that crashes a field unit.
  • Overstating the result.: A unit pass is logic evidence; name the hardware and interface questions it leaves open.
  • A unit suite earns trust when it shows both what it proved and what it deliberately did not.
iotclass.org

Deck summary

Key takeaways

A unit test checks one small piece of firmware logic on its own, with controlled inputs and a result you can read.

  • If you only need the intuition, this layer is enough: a unit test isolates one firmware behavior, feeds it controlled inputs, and checks a reviewable result.
  • A parser that turns a byte sequence into a reading can be fed a malformed sequence to confirm it rejects it instead of crashing.
  • Firmware is hard to unit-test when logic is welded directly to hardware — reading a register inline, calling a vendor driver, or sleeping on a real timer.
iotclass.org

Retrieval practice

Recall check 1 of 3

Test Tessa says: answer from memory, then check your reasoning.

Q1Why can a unit test for IoT firmware run in milliseconds and give the same result every time, and what does that speed cost it?

AIt isolates one behavior and replaces real hardware, network, and time with controlled stand-ins
BIt runs on the real device hardware, which is always faster and more accurate than a host computer
CIt is slow and unpredictable, which is why unit tests are run only at release time
DIt fully validates the device, so no further integration or hardware testing is needed
Show answer

Answer: A Isolation buys speed and determinism, but it also means a pass is a claim about logic under controlled inputs, not about the physical device.

iotclass.org

Retrieval practice

Recall check 2 of 3

Test Tessa says: answer from memory, then check your reasoning.

Q2You need to unit-test firmware logic that decides whether to raise a warning from a sensor reading, but the logic currently calls the sensor driver directly. What makes the logic testable, and which test double fits the sensor?

ALeave the direct driver call in place and run the test against the real sensor for accuracy
BDelete the assertion and just call the function to confirm it does not crash
CAdd a hardware seam, replace the driver with a stub, and assert boundary or error verdicts
DUse a strict mock that fails unless the function makes a fixed sequence of internal driver calls
Show answer

Answer: C A seam lets you substitute the dependency; a stub supplies the controlled readings the cases need so you can assert the decision deterministically.

iotclass.org

Retrieval practice

Recall check 3 of 3

Test Tessa says: answer from memory, then check your reasoning.

Q3A firmware module has thousands of passing unit tests and high line coverage, but field devices crash when a real sensor returns a value after a settling delay with a status byte set. The stub in the tests returned a clean reading instantly. What does this reveal, and what is the right response?

AThe stub had low fidelity, so the suite proved the logic only against unrealistic input
BThe coverage number proves the code is correct, so the crash must be unrelated hardware failure
CThe fix is to add more happy-path unit tests until coverage reaches 100%
DUnit tests are useless for firmware, so they should be removed in favor of field testing only
Show answer

Answer: A The green suite tested logic against a double that never reproduced real timing and status; that physical behavior belongs to the hardware-aware layer, and the unit record should have named it as open.

iotclass.org

Print reference

Answers

Answer key.

  1. A · Isolation buys speed and determinism, but it also means a pass is a claim about logic under controlled inputs, not about the physical device.
  2. C · A seam lets you substitute the dependency; a stub supplies the controlled readings the cases need so you can assert the decision deterministically.
  3. A · The green suite tested logic against a double that never reproduced real timing and status; that physical behavior belongs to the hardware-aware layer, and the unit record should have named it as open.
iotclass.org