Wednesday, July 22, 2009

Creating a Unit Test Plan to test the .NET application

Once the coding of the application is complete, the next phase is to ensure that it functions according to specification.

Although the compiler detects syntax errors, run-time errors and logical errors might not be revealed without thoroughly testing our program.

Hence there is a need to design an efficient test plan for testing of the component or application.

The Unit Test Plan

Most code contains errors on the first go. Thus, it is normal to  expect the code to have bugs when first written. However, a final application that is full of bugs or does not function according to specification is useless. We create a final version from a bug-laden first draft through testing.

Testing and debugging are separate but related activities. Debugging refers to the actual finding and correcting of code errors, whereas testing is the process by which errors are found. Testing is usually broken down by method. Individual methods are tested with a variety of inputs and execution parameters. This approach is called Unit Testing.

Designing Test Cases

As a minimal starting point when designing test cases, every line of code must be tested. Thus, if there are any decision structures in our method, we will need to define test cases that follow all possible branches of the code. Consider the following method:

Public Sub TestMethod (Byval bVal1 As Boolean, Byval bVal2 As Boolean)

If bVal1 = True Then

MsgBox (“Val1 is true”)

Else

MsgBox (“Val1 is False”)

End If

If bVal2 = True Then

MsgBox (“Val2 is true”)

Else

MsgBox (“Val2 is False”)

End If

End Sub

 

The number of test cases needed to run every line of code in this method is two: one case where bVal1 and bVal2 are true, and one case where bVal1 and bVal2 are false. Depending on the values of the parameters to be provided to the method in the code, the method execution could take paths not convered by the test case – for example, if bVal1 is True but bVal2 is false, the method execution will follow a path that was not convered in the test plan. To test all possible paths in this method requires two additional test cases: one where bVal 1 is True but bVal2 is false, and one where bVal1 is false but bVal2 is true. Therefore, at minimum our design for a unit test should include testing of all possible data paths.

Testing Data:

Testing the functionality of all possible data points is a good plan, but to make your application robust, you should also test whether it can handle different kinds of data. We want our application to behave normally and give expected results when data within normal parameters is provided, and it should gracefully and appropriately handle data that is outside of the specified bounds as well. Thus, to be thorough, we must test our application with a variety of data inputs ranging from normal to extraordinary. Specific types of data conditions used to create test cases are described as follows:

Normal Data:

It is important to test data that is within the normal bounds of program execution. Although it is usually impossible to test the entire range of normal data, your test cases should contain several examples of data that is normal for the program to process. This data should span the normal range of operation and should include the normal minimum and maximum values.

Boundary conditions:

Special considerations should be given to testing data on the boundaries of normal conditions. This includes the normal minimum and maximum values for program data, as well as values that are “off by one”. For example, to test the maximum boundary, we would include the maximum value, the maximum value minus one, and the maximum value plus one. This approach allows you to correct simple mistakes, such as using a > operator where a >= is required.

Example:

If e.RowIndex >= 0 Then

MsgBox DataGridView1(e.RowIndex).Cells(0).Value

End If

Bad Data

Using a variety of bad data in our test cases evaluates whether our program will crash in response to bad data, or, worse, function normally and return inappropriate results. We should test values that are well outside of the normal scope of operation, including zero for non-zero values, negative numbers for positive data, and so on.

Data Combinations

Our test plan should include a variety of combinations of the types of data. Errors might not be revealed until the correct data combination is used. For example, we might have a method that functions fine when each of its parameters is at its normal maximum, but fails when all of its parameters are at normal maximum. Similarly, combinations of known bad data can yield normal looking results. Consider the following method:

 

Public Function CalculateMySalary (ByVal Hours As Short, ByVal Weeks As Short) As Integer

Dim mySalary As Integer

mySalary = Hours * Weeks * WageConstant

End Function

 

Given that a normal range for Hours might be 0 to 40, and a normal range for weeks might be 0 to 52, this method functions normally with nominal input. However consider the following method call:

Dim result As Integer

Result = CalculateMySalary (-35, -50)

A combination of bad data returns a seemingly normal result. For this reason, our test cases should test a variety of possible data combinations.

To sum up the to do activities for an unit test plan

1. Begin by creating test cases that execute every line in the test unit

2. Add additional test cases until every possible path of data flow through the unit has been tested.

3. Add further cases to test variance in the data the unit will process. In addition to testing nominal data, we should test boundary conditions, bad data and different combinations of good and bad data

4. Determine the expected result of each test case in advance of the actual test.

5. Execute the tests and compare observed results with expected results.

No comments:

Post a Comment