-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the Bitcrush Testing workshop on writing testable, well-structured C++ for embedded Linux targets.
- How to structure C++ code so it can be unit tested
- How to write good unit tests and recognise bad ones
- How to handle hardware and library dependencies without making your code untestable
- Basic C++ knowledge
- Access to the target hardware for running tests
- The repository cloned and built. See the README
A reference page covering the testing pyramid, layering, dependency control, test double vocabulary, and how to organise tests alongside production code. Read this first or return to it as a reference throughout the workshop.
How to design new code with testability built in from the start, and how to introduce testability incrementally into a legacy codebase without a big-bang rewrite.
When to use a dummy, stub, fake, spy, or GMock mock. Covers practical patterns for writing and organising test doubles, and the mistakes that make them a maintenance burden.
A step-by-step walkthrough refactoring a realistic untestable class into a fully tested design. Covers interface extraction, adapter wrapping, constructor injection, and writing the test suite. Companion code in workshop/06_refactoring/.
Patterns for eliminating non-determinism caused by timing, concurrency, and hardware interaction. Covers virtual time, state machine sequencing, synchronous executors, ISR simulation, GPIO abstraction, and sequenced hardware fakes. Companion code in workshop/07_deterministic_testing/.
How to write unit tests against a documented public header without reading the implementation. Covers writing testable Doxygen contracts, the pimpl idiom for hiding internals, deriving tests from documentation clauses, and using documentation coverage as the completeness metric. Companion code in workshop/08_blackbox_testing/.
How to run testing as a repeatable process. Covers who writes tests and when, the CI gate, the definition of done, and the components of a test plan.
A ready-to-fill Markdown template covering all ten plan components: header, scope, objectives, test levels, hardware requirements, test cases, coverage goals, pass/fail criteria, known limitations, and revision history.
A ticket template with mandatory quality gates and a definition of done checklist. Ensures that testing obligations are defined before implementation starts and are visible to code reviewers.
Learn the difference between monolithic code that is impossible to test and a layered design that isolates hardware from business logic.
See what makes a unit test good or bad. Covers test naming, isolation, determinism, and using test doubles.
Learn the adapter pattern to wrap vendor libraries and hardware APIs so your logic stays testable, even when tests can only run on the target.
Learn how to test Qt5 signals and slots with GTest and QSignalSpy. Covers direct vs queued connections, the QCoreApplication requirement, and common mistakes.
Learn constructor injection in plain C++ and with Qt objects. Shows hand-written fakes, spy objects, and GMock mocks, and explains why injecting interfaces makes every collaborator replaceable in tests.
Hands-on refactoring of a realistic untestable class into a fully tested design, step by step. Companion code in workshop/06_refactoring/.
Testing patterns for timing, concurrency, and hardware interaction. Companion code in workshop/07_deterministic_testing/.
Writing unit tests from a Doxygen-documented public header without reading the implementation. Companion code in workshop/08_blackbox_testing/.
- Home
- Test Architecture Patterns
- Designing for Testability
- Effective Use of Test Doubles
- Refactoring Toward Testability
- Deterministic Testing
- Testing Processes
- Test Plan Template
- Development Ticket Template
- Black-Box Testing from Doxygen
Module 01 — Code Structure
Module 02 — Unit Tests
Module 03 — Hardware Dependencies
Module 04 — Qt Signals & Slots
Module 05 — Dependency Injection