Path Testing

Hello, and welcome back to my blog.

This week I will be sharing what I have been learning about path testing. Path testing is a white box method of tests that is used to design test cases by using the source code of a program to find every possible executable path. The bug presumption for path testing is such that the program has gone wrong in some way, causing it to follow a different path than desired.

Path testing utilizes Cyclomatic Complexity to establish the quantity of paths, and then tests cases for each path are generated. Developers can choose to execute some or all paths through when performing this testing. Path testing techniques are perhaps the oldest of all structural test methods. Path testing is most useful for unit testing new applications.

It provides full branch coverage, but does so without covering all possible control flow graph paths. The four part process to path testing begins with drawing a Control Flow Graph of the software that is being tested. Next, Cyclomatic Complexity of the program is calculated based off Edges, Number of vertices, and Program factor. Now, we can use the data calculated in the first two steps to find a set of paths to test. The computed cyclomatic complexity equals the set’s cardinality. Finally, we will develop test cases for each of the paths determined in previous steps.

Path Testing process:

Path testing is beneficial because it focuses test cases on program logic. It helps to find all faults within the code and reduces redundant tests. In path testing, all program statements are executed at least once. Thank you for taking the time to visit my blog and join me on my growth as a software developer.

Sources:

http://www.mcr.org.in/sureshmudunuri/stm/unit2.php

https://ifs.host.cs.st-andrews.ac.uk/Books/SE9/Web/Testing/PathTest.html

https://www.geeksforgeeks.org/path-testing-in-software-engineering/

Data Flow Testing

Data flow tested is used to find issues such as:

  • a variable that is used but never declared
  • a variable that is declared but never used
  • a variable being de allocated prior to its use
  • a variable that is defined multiple times before being used

Some advantages of using data flow testing to find issues in a program include, but are not limited to, finding variables that are used but not defined ever, and finding a variable that has been defined numerous times before it is even used.

Data flow coverage can be classified into the following categories based on “sub-paths” and “complete path”:

  • All definition coverage: Covers “sub-paths” from each definition to some of their respective use.
  • All definition-C use coverage:“sub-paths” from each definition to all their respective C use.
  • All definition-P use coverage: “sub-paths” from each definition to all their respective P use.
  • All use coverage: Coverage of “sub-paths” from each definition to every respective use irrespective of types.
  • All definition use coverage: Coverage of “simple sub-paths” from each definition to every respective use.

Mockito mocking

On the Vogella Mockito tutorial page, there is a brief overview and explanation of what mocking is and what a mock object is. There is a simple diagram showing the sequence of what typically happens when you use Mockito in your tests. This tutorial also mentions that when using the Mockito libraries, it is best to do so with either Maven or Gradle, which are supported by all of the modern IDEs. Here you can also find code examples, and even where to put them in your code. This tutorial is packed with visual representation of the information given and I find that to be extremely helpful.

I would say this particular article/tutorial can be very helpful in bettering one’s understanding of how to use Mockito. It’s filled with tips and simple to understand diagrams, explanations and code examples. It even dives into using the spy() method to wrap Java objects, mocking static methods, creating mock objects (in the exercise provided, you can create a sample Twitter API), and testing an API using Mockito.

I have included in this blog post two other articles I found interesting and informative on the subject of Mocks/Mocking

C o d e C o v e r a g e T e s t i n g

Cover your tests

Welcome back, I am going to explain why you should be running most of your tests with some sort of code coverage. Code coverage is a software testing metric that analyzes how effective your tests are when ran with your code. Code coverage enables you to see the degree to which your code has been implemented. It also helps you to determine how successful unit tests are by checking the degree to which your code is covered by them. Code coverage percent is calculated by items tested by dividing elements tested by elements by elements found.

Code coverage enables you to improve the efficacy of your code by having a statistical analysis of code coverage. The test cases your currently running without code coverage may be less effective than you realize. Running with code coverage allows you to identify parts of your software that have not been examined by your test cases. This not only makes better code but it saves time because it gives you a clearer picture of where you need to refactor.

Code coverage enables you to identify parts of the software that are not implemented by a set of test cases.

How is code coverage calculated?

Well, that depends on what tools you’re using. However the common tools combine some of the following types:

  • Line coverage: percent of lines tested
  • Functions coverage: percent of functions called
  • Conditions coverage: percent of boolean expressions covered
  • Branch coverage: percent of branches executed

Are all code coverage types created equal?

When I first learned about code coverage, I assumed that line coverage must be superior, because hitting every line must be most important and probably will include most methods. While this is important it will miss out on a few things. Consider the following code from a stackoverflow answer:

public int getNameLength(boolean isCoolUser) {
    User user = null;
    if (isCoolUser) {
        user = new John(); 
    }
    return user.getName().length(); 
}

When you call this method with the boolean variable isCoolUser set to true, you will have your line coverage come back 100%. However, this method has two paths;

  1. boolean is true
  2. boolean is false.

If the boolean is true, all lines are executed, and code coverage will return 100%. What we don’t see with line coverage is that if you call this method with the boolean set to false, you will get a null pointer. Line coverage wouldn’t show you this bug, whilst branch coverage would. For these reasons, best practice is to use a coverage tool that examines multiple types of code coverage

You’ve convinced me, so how do I start?

Code coverage comes built into most IDE’s. In intellij, when you open the run drop-down menu, its two buttons below, “Run with Coverage”. I have found this tool incredibly useful/invaluable in my coding. Since learning of it, I have not run tests without using coverage. There have been a few instances where I created test classes that passed but I wasn’t aware just how terrible they could be. Using code coverage has made me learn more and see my mistakes much more easily. Lines I thought were testing the code, I could comment out and see if it reduces code coverage and learn from that. In Intelli-j’s code coverage, lines that have been executed are green while lines that aren’t are red.

Other code coverage tools are listed below:

SonarQube

JaCoCo

Clover

Selenium

Carina

Cucumber

Good coverage can’t fix bad test writing practices.

If your tests aren’t comprehensive, covering multiple possibilities, coverage won’t save you.

Thanks for taking the time to stop by and read my blog.

I learned quite a bit of information from the following links:

https://ardalis.com/which-is-more-important-line-coverage-or-branch-coverage/

https://stackoverflow.com/questions/8229236/differences-between-line-and-branch-coverage/8229711#8229711

https://www.softwaretestinghelp.com/code-coverage-tutorial/#Methodologies