| Code Coverage Process |
|
Code Coverage in Java, C and C++ This article will focus on explaining how code coverage is achieved in Java, C and C++. In the previous tutorials, we have already defined what code coverage is as well as its functionalities.
I - Code coverage and its functionalities Code coverage algorithms provide a means to assess the level of testing that have been performed on a source code. Therefore, code coverage algorithms work by looking at the source code. Code coverage belongs to the structural testing category because of its assertions made on the internal parts of the program and not on system outputs. As a result, code coverage aims at finding parts of the code that are not worth testing. Functionalities of code coverage are as follows:
II - Java and code coverage The Java programming language, like any other programming language such as C/C++, Pascal and so forth, provides a means to express tenets. Java is a language that defines a runtime environment in which user-defined classes will be run by the cross platform utility called Java Virtual Machine. Instances of these user-defined classes may represent real-world data that is stored in a database, file systems, or mainframe transaction processing system. Additionally, small-footprint environments often require a means of managing persistent data in local storage. Java was created by Sun Microsystems as a competitor to C++. The following paragraphs will focus on explaining how the two of the five code coverage functionalities can be applied to a Java program. a- The statement coverage As we already know, its aim is to determine the number of lines in the source code that have been executed by the test suites. In Java terms, this can be identified as the number of statements in a method or class that have been run. An immediate advantage of this type of coverage is its ability to reveal useless parts of a program. On the other hand, this coverage does not help coders find any bugs in the source code. As a result, you may have identified the most interesting parts of your program and these parts containing some nasty bugs. Too much talking... let us see it works in practice with a simple Java snippet. In order to enable the task to the reader, Java keywords are highlighted in red just like a Java compiler would have done. package myPackage; public class StatementCoverage { public int ReturnUserInput (int anumber, boolean FirstCondition, boolean SecondCondition, boolean ThirdCondition) if (FirstCondition) { anumber++; } if (SecondCondition) { anumber--; } if (ThirdCondition) { anumber = anumber; } return anumber; } } The statement coverage class is a simple snippet of a function which accepts four arguments: a number typed by the user of the program and three Boolean conditions. These conditions only take two values (true or false). The statement coverage class has got only one method: the ReturnUserInput which performs an operation on the user’s input and returns it according to a condition. The next thing we could do is to create a JUnit test suite satisfying the requirement and ensuring successful statement coverage. Here it is: public void JUnitTestForStatementCoverageTTT() { StatementCoverage ClassConstructor = new StatementCoverage(); int returnValue = StatementCoverage.ReturnUserInput(1,true,true,true); assertEquals (1,returnValue); } The ReturnUserInput has got a very nasty bug. Let us glance at its condition statements. We can easily note that its first or second will return true whereas the third one will return false. Therefore, the return value of the function will definitely not be the initial user input. Such errors are very hard to find even by experienced coders; the trickiest part of the story is that the statement coverage will not help you at all! There is a way around this shortage: the branch coverage. Due to space requirements, it will not be covered in this article.
b- The path coverage This type of coverage aims to return the number of possible paths executed by the test suites. By path we mean an execution flow from the beginning to the end of a given method. Mathematicians know that with N conditions, there are 2^N possible paths. There may be cases of indefinite loops if methods are embedded. In Java, we will use a tenet known as cyclomatic complexity as a way around this problem. The cyclomatic complexity of a given method can be defined as the number of unique conditions in a method plus 1. This concept will help us find the exact number of linearly-independent paths in a method. The rationale of linearly-independent paths is to find the smallest set of paths that can be combined to each other in order to create every other possible path of that method. Let us move to a practical example. We will make use of the same Java snippet as in the previous coverage. At first, we need to create the size of linearly-independent paths also known as the basic set. We can easily work out the cyclomatic complexity of the ReturnUserInput method which 3 conditions + 1 = 4. These paths are as follows: Path 1: Any path will do for our baseline, so we pick true for the decisions' outcomes (represented as True True True). This is the first path in our basis set. Path 2: To find the next basis path, we'll flip the first decision (only) in our baseline, giving us False True True for our desired decision outcomes. Path 3: We flip the second decision in our baseline path, giving us True False True for our third basis path. In this case, the first baseline decision remains fixed with the true outcome. Path 4: Finally, we flip the third decision in our baseline path, giving us True True False for our fourth basis path. In this case, the first baseline decision remains fixed with the true outcome.
Therefore our basic paths are: True True True , False True True , True False True, and True True False. In the previous Java snippet, it is straightforward that the following methods JUnitTestForStatementCoverageTTT () and void JUnitTestForStatementCoverageFTT() help identify the bug that was unfortunately not seen by both the statement and branch coverages. It is also handy to notice that the number of basic paths linearly increases with the number of conditions. Testing the four basis paths achieves the goal of this type of coverage as stated at the beginning of this section, making the other paths extraneous. If you had started with FFF as your baseline path, you would wind up with the basis set of (FFF, TFF, FTF, FFT), making the TTT path extraneous. Both basis sets are equally valid, and either satisfies our independent decision outcome criterion. |
Coverage Process


