In short
In embedded C a unit is a single function, the smallest reasonable test object of a C program, while in C++ the unit is a method, which cannot be executed without an object. Unit testing exercises that unit in isolation through a generated test driver that supplies the startup code, the main() entry point and the call, with stub functions replacing the units it calls, so the observed result depends on the unit alone.
The Word “Unit” Is Doing More Work Than You Think
Ask five embedded engineers what a unit test is and you get five answers: a call in a main() somewhere, a suite in CI, a bring-up script, a number on a dashboard. That ambiguity is expensive, because a safety assessor asking for unit test evidence is asking a precise question.
What Counts as a Unit in C
Razorcat, the Berlin developer of TESSY, puts it plainly in the TESSY 5.1 Manual glossary: a unit is a single function, the smallest reasonable test object of a C program. A Test Object is “the function to be tested,” and a TESSY module is built primarily from the test object (in C, a function in the sense of C) plus source files, compiler settings, interface description and test data.
The derivation is in the same manual. Part 4 of IEC 61508 defines a software module as a construction consisting of procedures and/or data declarations that can interact with other such modules, and for embedded software written in C, Razorcat notes, we can take a C-level function as a module. To avoid confusion with C source files, the manual calls those functions units. The standard says “module,” your build system says “translation unit,” and the discipline means one C function at a time.
What Counts as a Unit in C++
In C++ the unit is a method, and the mechanics change because a method cannot be called without an object. Razorcat’s TESSY Application Note #038, “Using C++,” is explicit:
- On opening a module, TESSY analyzes the source files and provides the list of class constructors, methods and functions for all classes in them. The interface of each testable method appears in the Test Interface Editor, with the class member variables.
- Constructors appear as test objects in their own right. Destructors do not appear in the Test Data Editor, because calling one destroys the object and TESSY cannot read values from destroyed objects.
- Unlike normal C tests, per Razorcat, you always need a C++ object to execute any method. That instance comes from a special
thisvariable: reuse one across test cases and it retains internal state, or create a new one per test step. - Every method can throw, so a special global output variable named “throws exception” is specified per test step. Overloads are disambiguated by signature: per Razorcat, the test object name includes the whole method signature.
Interface Analysis: The Unit’s Real Contract
Razorcat’s manual defines the interface of a unit as the input variables, meaning variables read by the unit, together with the output variables, meaning variables written by it. A variable can be both, and the return value, if present, is always an output. Crucially, the structure of a test case follows from the structure of the interface.
That is why unit testing is black-box work: per Razorcat, it tests at the interface of the unit and does not consider its internal structure. In TESSY the interface description, the passing direction and type of each parameter, global and external variable, is determined automatically and made changeable in the Test Interface Editor. Razorcat is equally clear about what falls outside: the interaction of units is not tested during unit testing, and interrupt behaviour is out of scope.
Test Drivers and Stubs
A C function is not a program. Something has to start the microcontroller, enter main(), set the inputs, call the function and capture what comes back. Razorcat’s glossary defines a Test Driver as C source files generated by TESSY for test execution, compiled and linked to build an application that prepares the input data, calls the test object and stores the actual result data. Per the manual, that driver carries startup code for the embedded microcontroller, the main() entry point, the call to the unit under test, and stub code where required.
A stub function, per Razorcat’s glossary, is a piece of code used to stand in for some other programming functionality. Per Application Note #004, “Using Stub Functions,” TESSY recognizes all external functions called by a test object and can provide stubs to be called instead, and local functions defined within the source file can also be replaced. Advanced Stubs handle the stub’s parameters and return values like normal inputs and outputs, so they surface in the Test Data Editor and the report.
Isolation Is the Whole Point
Razorcat’s manual states the definition that matters at audit: during unit testing of C programs a single C-level function is tested rigorously and in isolation from the rest of the application, where isolated means the test result does not depend on the behaviour of the other units, achieved by directly calling the unit under test and replacing calls to other units with stub functions.
The counter-example is sharper. Razorcat’s manual describes an “original binary test” approach, loading the unchanged application and running it until the unit is eventually reached. Its documented disadvantages: no control over when, or whether, the unit is reached; stubs cannot be used, so a unit is always tested using the other units of the application and errors of called units may show up during the test; and arbitrary test data cannot be used. Razorcat concludes that one could even insist this is not a unit test in its strictest sense. Certification authorities agree: EASA’s Certification Memorandum CM-SWCEH-002 describes coverage measurements taken by “executing requirements-based tests of that module in isolation from other program modules.”
On-Target Versus Host Execution
Host execution is fast and cheap. Target execution is what the certificate is about. Razorcat’s manual states that for embedded software it is essential that the unchanged source code, with all its non-ANSI keywords and peculiarities, is used for testing. Its example is a cross compiler permitting bit fields narrower than the integer size, which ANSI C forbids but which suits the target perfectly, and it observes that unit test results are worthless if that size cannot be maintained during the tests. It adds that the concluding tests must at least execute on the actual hardware, that is, the embedded microcontroller.
| Host or simulator | On target | |
|---|---|---|
| Compiler | Per Razorcat’s Application Note #048, verification of the TESSY core workflow covers tests conducted on a Windows host system using the GNU GCC compiler | Your cross compiler, preferably the exact version used for the application (per Razorcat) |
| Compiler-specific behaviour | Not exercised, so constructs such as narrow bit fields are absent | Represented, which is why Razorcat calls unchanged source essential |
| Memory constraints | Effectively none | Must fit target memory, hardest on single-chip parts (per Razorcat) |
| Typical use | Fast feedback, CI regression runs | Concluding tests, which per Razorcat must at least run on the actual hardware |
Razorcat’s TESSY 5 flyer lists test execution on hosts, simulators and hardware, so both columns are the same tool. Crossing between them is where adaptations bite, which is why Razorcat ships test driver communication tests, documented in Application Note #048, “Using the Test Driver Communication Tests.” They check the transfer of test data to the target and the transfer of data back from it, and Razorcat states that when TESSY is used within a safety related environment it is strongly recommended to run them, after initial project setup and after any change to the environment settings. For the debug-probe side, see our guide to TESSY on target with SEGGER J-Link.
Why the Standards Require This Rather Than Suggest It
Unit testing is not a good practice the safety standards nod at. It is normative text with “shall” in it.
IEC 61508-3
IEC 61508-3:2010 clause 7.4.7.1 states that each software module shall be verified as required by the software module test specification developed during software system design; clause 7.4.7.2 that this verification shall show whether or not each software module performs its intended function and does not perform unintended functions; clause 7.4.7.3 that the results shall be documented.
The annex tables set the intensity. In Table A.5, dynamic analysis and testing is Recommended at SIL 1 and Highly Recommended from SIL 2, while functional and black-box testing is Highly Recommended at every SIL. Table B.2 lists 100 percent structural test coverage targets for entry points, statements, branches and conditions/MC/DC, rated Recommended or Highly Recommended as the SIL rises, with a footnote that where 100 percent cannot be achieved, for example on defensive code, an appropriate explanation should be given. More on our IEC 61508 page.
DO-178C
Airborne software uses different vocabulary for the same activity. EASA’s Certification Memorandum CM-SWCEH-002 quotes ED-12C/DO-178C section 5.0, that low-level requirements are software requirements from which source code can be directly implemented without further information, and refers throughout to low-level testing against them. The purpose of structural coverage analysis, per the same memorandum, is to detect code that was not exercised during requirements-based tests, and it sets the criteria per software level by citing Objectives 5, 6 and 7 of Annex A Table A-7. DO-178C, dated 13 December 2011, is recognised by the FAA in Advisory Circular AC 20-115D as an acceptable means of compliance. See our DO-178C page.
ISO 26262
Per Perforce, ISO 26262 is a risk-based safety standard derived from IEC 61508, Part 6 covers product development at the software level, and Part 6 includes several tables that define the methods that must be considered in order to achieve compliance. Razorcat ties one TESSY capability directly to the standard: Call Pair Coverage checks whether all call points of functions or methods within the test object have been executed at least once, which per Razorcat meets ISO 26262 requirements as an alternative coverage procedure for integration tests instead of function coverage. For the ASIL view, see our ISO 26262 Part 6 unit testing checklist.
| Standard | What it calls the activity | Coverage expectation, as published |
|---|---|---|
| IEC 61508-3:2010 | Software module testing, clause 7.4.7, written with “shall” | Table B.2: 100 percent entry point, statement, branch and condition/MC/DC coverage, rated R or HR by SIL |
| DO-178C | Low-level testing against low-level requirements, judged by structural coverage analysis | Per EASA CM-SWCEH-002: statements at Level C; plus decisions at Level B; plus MC/DC at Level A |
| ISO 26262 | Unit-level verification within Part 6, product development at the software level | Per Perforce, Part 6 tables define the methods that must be considered; per Razorcat, Call Pair Coverage meets ISO 26262 for integration tests |
If a tool produces your evidence, its own status matters. Razorcat’s FAQ states that TESSY V5.1 is qualified for safety-related software development, and TESSY carries TUV SUD certificate Z10 078930 0004 Rev. 01. The certification report behind that certificate, RB84018C version 2.0 of 13 November 2023, classifies TESSY as an offline support tool of class T2 under IEC 61508-4:2010 and records it as suitable for use in safety-related development according to IEC 61508:2010 and EN 50128:2011/A2:2020 for any SIL, ISO 26262:2018 for any ASIL, and IEC 62304:2006+A1:2015 for any software safety class.
One last distinction, since teams still conflate them. Unit testing is dynamic, running the code and comparing actual results against expected ones, and Razorcat lists eight coverage measurements in TESSY including statement (C0), branch (C1), decision and MC/DC. Static analysis reasons about code without running it, and Perforce Helix QAC and Klocwork sit on that side. Evidence packages generally need both, as covered in our TESSY plus Helix QAC guide and MC/DC coverage guide.
Related reading
- Is 100% Code Coverage Enough?, the coverage levels and what each one buys you
- Test Case Design with the Classification Tree Method, how to design the cases once the harness exists
- How to Evaluate a Unit Testing Tool, picking the tool that drives your toolchain
- Razorcat TESSY, the tool these techniques are run with in India, the UAE and Sri Lanka
Getting Started in India, the UAE and Sri Lanka
GSAS Micro Systems is the authorized Razorcat engineering partner for India, the UAE and Sri Lanka. Our engineers set TESSY up against your actual cross compiler and debugger, define the interface and stub strategy for your first modules, and get host and on-target execution running side by side, so the fast loop and the certification loop both exist from day one. We support teams from Bengaluru, Hyderabad, Chennai, Pune, Mumbai and Delhi NCR, with INR invoicing and one support channel.
Razorcat’s public product pages currently document TESSY 5.1. If your programme needs the scope and availability of a later version, ask GSAS and we will confirm what applies to your project. Request a TESSY evaluation or read more about Razorcat and GSAS.
Also appears in:
Interested in Razorcat tools?
Talk to our application engineers for personalized tool recommendations.
More from Razorcat
View all →