When we talk about software unit testing, the first question I always ask is “What is a unit for you?”. This can be a very controversial topic, as there are different understandings out there. Some have even given up on trying to find a common agreement about what a unit is and use different terms instead. Using my experience in software development projects, I will try to explain what my understanding of a unit is and what the impact on quality is. “What does this have to do with software quality?” one might ask. Let’s wait and see.
Definition of “software unit”
I admit that you can find the term “unit”, “functional unit” or “software unit” in the glossary of many standards, e.g. AutomotiveSPICE, ISO 62304 (referencing ISO/IEC 90003:2004), IEC 61508 (referencing ISO/IEC 2382:2015). The most precise definition, which at the same time combines most of the aspects of the beforementioned definitions without contradicting others, can be found in ISO 26262. This definition is as follows:
"Software unit = an atomic level software component of the software architecture that can be subjected to stand-alone testing."
Sounds quite clear, but why are there still different interpretations? Because the terms in this definition are context-dependent, especially the word “atomic”. Taken by itself, the term means that something is not further subdivided.
I can hear many of you say: “This means that each function in the source code is a unit.” (Since each module contains functions, it can be subdivided) And: For object-oriented languages, the discussion is normally about classes and methods. I confirm that this is a common understanding. Why then write this article? Because in my opinion this understanding is not universal, and in more ways than one.
Understanding the term “unit”
If you apply this interpretation then one could also ask for each of these functions:
- Can they be further subdivided?
- What about functions that call other functions?
- What about macros?
Where to stop? Better stop before asking these questions.
First, we must clarify where the software unit is defined. Taking another look at the definition above, there is no mention of terms like source code or implementation. The term is used exclusively in combination with the development of software architecture. Hence, we must come to the conclusion that it is not the source code where we have to look for the software unit definition. Rather, the unit is an abstract idea of a possible implementation that exists in the mental model of the architecture.
Second, let’s take a look at the term “atomic” in this context. Software architecture does not have an unlimited level of detail. At some point, the architecture is detailed enough for implementation. There, the decision is taken to not further subdivide the components, meaning they become the atomic elements. And this volitional decision makes these detailed components units. Everything that happens inside of these components (structure and behavior) does not to have to be transparent for the other components. These other components only rely on the availability, the interfaces, and the expected behavior. The details of the internals of these atomic-level software components are specified in the detailed design or the unit specification. But this does not change the definition of the component as a unit.
Putting the unit to the test
What is also part of the definition is that a software unit can be subjected to stand-alone testing. Stand-alone testing means that no other parts (of the architecture) are needed to fully test the subject under test.
As elements of the architecture, these components have at least one interface and allocated requirements. This means we know how to get data in and out and what is expected from these units’ behavior. Thus, we have almost everything we need for testing them. The only thing missing is the implementation. The implementation is the realization of the architectural design, which means the translation from one mental model (the architecture) to another (the source code). And for this translation, the following quote is very true:
"A map is not the territory". - Alfred Krzybski
Although this translation must be as literal as possible (following the architectural design by the letter) there is still a certain degree of freedom. As a consequence one software unit (in the architecture) can end up as one single function (in the source code), while another unit is implemented using multiple functions. There can even be files containing multiple units or units spreading over multiple files.
Since this can be the case in the same project it is very difficult to identify the unit solely in the source code. Now, you should understand, why I said in the beginning, that the statement, that one unit always equals one function, is not universal.
One function can be the interface to test the realization of a unit. But architectural information is required to identify the whole unit. The figure below shows an example of an architectural element representing one unit with interfaces and allocated requirements. In this case, the unit is translated or implemented as two separate files. Therefore, if the source files are tested individually, you have not fully tested the unit as a whole
Limitations of these freedoms during implementation, e.g. that “a unit shall not be translated into more than one module”, are part of best practices and guidelines. But again, even these guidelines don’t change the definition of a unit, they may only make the translation more straightforward.
Software units and software quality
What does it have to do with quality? A lot. Defining the right level of detail will help you focus on the right activities.
Taking a development based on the automotive standard ISO 26262 as an example:
- The requirements have to be mapped to units, hence having units with the “correct” size will make this easier. If the units are too small, there may be the need to refine the requirements further than necessary. In the end you will have requirements that are so close to implementation that they provide no additional value, neither for the architectural design nor for testing.
- The functional behavior and internal design of units have to be specified, and this applies to all software units. If the units are too small, this heavily increases the documentation effort. The documentation of the units must be detailed enough for implementation. And being detailed enough for the implementation still leaves at least some work to be done by the developers writing the source code (unless you plan to fully generate the code out of your model). Units that are too small cause the specification to overshoot this target by being overly detailed and by anticipating the implementation.
- Evidence for testing must be generated for each unit. So, more software units mean more testing and more documentation. And considering the overly detailed requirements and specifications you end up testing rather the implementation than the intended functionality.
The following figure illustrates two different levels of detail for the architectural elements, while starting from the same requirements. On level A the units stay more abstract, while on level B the units are further refined. This leads to additional requirements, more details to be documented and more tests to be created. Both levels lead to the same implementation.
If quality for you means “the more the better”, this may sound positive. But experience shows that this normally means that corners are cut, leading to even worse quality in the end: documentation is not up to the expected level in the beginning, is not maintained and in the end becomes useless (it has been generated to comply with the process and documentation requirements, but not for added value). Tests are written based on the implementation instead of the requirements, as there is no benefit in doing it differently.
It’s adding by subtracting. Having software units that are more abstract does not mean that they contain less value. The reverse is true. Abstract means something that concentrates on itself the qualities of a larger item, or multiple items. And this is exactly what a unit should be like when compared with its realization. Reducing the level of detail to a sufficient level will help keep the requirements meaningful, the specification maintainable and the unit tests valuable. So, do less for more quality.
Conclusion: What is a software unit
We started with the question “What is a unit for you?”. For me, the unit is a part of the software architecture with a level of detail that has been deliberately chosen to be sufficient for implementation, but not anticipating it. Applying this approach consistently from requirements to tests leads to a higher quality of all related development artifacts, as all of them provide added value and do not add redundancy. Let me put it as a request: Look for your units in the architecture and don’t make them too small!
Maybe next time, we can talk in detail about unit testing. But for now, I kindly invite you to join the discussion and leave a comment. Do you agree? Or is this complete nonsense for you?
7 thoughts on “What is a software unit?”
Thanks
There is way more decision factors such as maintainability, complexity metrics etc. Also the article is misleading saying you need to test more – actually trying to test a bigger SW unit to achieve the needed coverage metrics might be very time consuming.
Thank you for the feedback. I agree that there are many factors that can be used as drivers for the development of the architecture. I would also like to refer you to my article on measuring quality, which also looks at other factors: What is software quality and how to measure it?
When weighing up the effort required for the tests, the significance of the tests should also be taken into account. If I have requirements that are too simple (which also have to be fully covered), the significance of the tests also decreases. I additionally have the effort at higher levels. In my opinion, test cases for more abstract requirements make more sense and are more valuable, even if they are more complex.
Great article, well structured and articulated.
Great article! Small clarification though. Diagrams in this hint that a unit may have more than one interface functions. Is this not violating “One entry and one exit point in subprograms and functions” Design principles for software unit design and implementation of ISO 26262?
Thank you for the feedback! It is not violating the design principles, as a unit may consist of more than one subprogram or function. This can be derived from the same requirement (8.4.5 of ISO 26262-6:2018), but in the text in sub-item a. There it reads that among others the following property has to be achieved: “correct order of execution of subprograms and functions within the software units”.
Thanks for your reply! This is great reference from ISO 26262 which proves that a unit when realized in C can have more than one C functions. These C function preferably can be part of a single C file or spread over multiple C files, it does not matter.
But does this also mean that a unit can have multiple interfaces? Multiple interfaces implies that a unit provides more than one functionality in same functional area. e.g. Can we call library a unit which provides services on linked list, such as node addition/deletion, searching, sorting?