How To: Get 100% code coverage with C# Switch Statements

Recently I started looking at 100% code coverage for my unit tests. Although, this is a good thing to achieve, it could become a daunting  task specially if you have foreach or switch statements. Let me illustrate the problem using the switch statement. Here is some sample code of a class VehicleType with a lone method PrintVehicle which accepts an enum VehicleTypes and prints the appropriate vehicle name using switch statement.

    1: public class VehicleType
    2:     {
    3:         public void PrintVechicle(VehicleTypes vt)
    4:         {
    5:             
    6:             switch (vt)
    7:             {
    8:                 case VehicleTypes.Bicycle:
    9:                     Console.WriteLine("Bicycle");
   10:                     break;
   11:                 case VehicleTypes.Car:
   12:                     Console.WriteLine("Car");
   13:                     break;
   14:                 case VehicleTypes.Motorcycle:
   15:                     Console.WriteLine("Motorcycle");
   16:                     break;
   17:                 case VehicleTypes.Scooter:
   18:                     Console.WriteLine("Scooter");
   19:                     break;
   20:                 case VehicleTypes.Truck:
   21:                     Console.WriteLine("Truck");
   22:                     break;
   23:             }
   24:         }
   25:         public enum VehicleTypes
   26:         {
   27:             Bicycle = 0,
   28:             Scooter = 1,
   29:             Motorcycle = 2,
   30:             Car = 3,
   31:             Truck = 4,
   32:         }
   33:     }

 

The following is a test method for the PrintVehicle method, as you see it has covers all the VehicleTypes.

 

    1: /// <summary>
    2: ///A test for PrintVechicle
    3: ///</summary>
    4: [TestMethod()]
    5: public void PrintVechicleTest()
    6: {
    7:     VehicleType target = new VehicleType(); 
    8:     target.PrintVechicle(VehicleType.VehicleTypes.Bicycle);
    9:     target.PrintVechicle(VehicleType.VehicleTypes.Car);
   10:     target.PrintVechicle(VehicleType.VehicleTypes.Motorcycle);
   11:     target.PrintVechicle(VehicleType.VehicleTypes.Scooter);
   12:     target.PrintVechicle(VehicleType.VehicleTypes.Truck);
   13: }

 

You would expect code coverage of 100% as we test all the cases for switch statement. But, the code coverage shows only 92.31% covered and 1 block of code missing as shown below.

 

codecoverage

Lets look at the code and see what was covered in the test. Amazingly everything seems to be covered so which block is not being tested. It turns out that compiler adds some additional code at the IL level during debug mode which is responsible for this erroneous behavior. Similar problem exists for foreach statement, we can fix this by using for statements. But, for statement poses different problem as the alternative is complex if else conditions. Lets look at some alternatives to fix switch statement issue.

image

In this case we add a new enum value which we will not handle in the switch statement. For example we add a new enum value "None" to the VehicleTypes and include that in our test case without handling the new value in the switch statement. Please note that this is a breaking change when it comes to code compatibility, specially if you are writing a framework.

 

    1: public enum VehicleTypes
    2: {
    3:     Bicycle = 0,
    4:     Scooter = 1,
    5:     Motorcycle = 2,
    6:     Car = 3,
    7:     Truck = 4,
    8:     None=5
    9: }
   10:  
   11: /// <summary>
   12: ///A test for PrintVechicle
   13: ///</summary>
   14: [TestMethod()]
   15: public void PrintVechicleTest()
   16: {
   17:     VehicleType target = new VehicleType(); 
   18:     target.PrintVechicle(VehicleType.VehicleTypes.Bicycle);
   19:     target.PrintVechicle(VehicleType.VehicleTypes.Car);
   20:     target.PrintVechicle(VehicleType.VehicleTypes.Motorcycle);
   21:     target.PrintVechicle(VehicleType.VehicleTypes.Scooter);
   22:     target.PrintVechicle(VehicleType.VehicleTypes.Truck);
   23:     target.PrintVechicle(VehicleType.VehicleTypes.None);
   24: }

Now run the tests and check the results, amazingly we have 100% code coverage. I know that this may not work for all switch statement problems but at least gives you an option to achieve that perfect 100% coverage.

Some MSDN links talking about IL code generated for switch statement.

https://forums.microsoft.com/msdn/ShowPost.aspx?PostID=3527731&SiteID=1

Thanks

Anil Revuru

Comments

  • Anonymous
    August 20, 2008
    You don't have to modify the enum..  Simply add a call like arget.PrintVechicle((VehicleType.VehicleTypes)666); to your test.Anyway, for me this is just another proof that 100% code coverage isn't and shouldn't be a requirement for good software development.
  • Anonymous
    August 21, 2008
    Actually, it's really telling you that you're switch block is missing adefault:     throw new System.IndexOutOfRangeException();
  • Anonymous
    August 21, 2008
    You both are right, you have to add a new call with some arbitary value and add a default case with exception. This way any new enum values will be regressed. But on the other hand, there are some cases which you cannot achieve the same, i.e as tim says another proof why 100% should not be a requirement.
  • Anonymous
    January 29, 2015
    You dont call Assert in your test method. can you please tell me what happen if the test case get failed
  • Anonymous
    April 06, 2018
    The comment has been removed