Monday, February 23, 2009

Unit Testing

Unit Testing is a test that validates that the individual elements of the source code are working properly. A unit is the smallest testable peice of code of the application. The goal of Unit Testing is to isolate each part of the program and show that the individual parts are correct.
As soon as the programmer develops a unit of code, unit is tested for varous scenarios. As the application is built it is much more economical to find and eliminate the bugs early on. Hence unit testing is the most important of all the testing levels. As the software project progresses ahead, it becomes more and more costlier to find and fix the bugs. In most cases it is developer's responsibility to deliver the Unit-Tested code.
Unit Test Tasks and Steps :
1. Create a Test Plan.
2. Create Test cases and Test Data.
3. If applicable create scripts to run the test cases.
4. Once the code is ready execute the test cases.
5. Fix the bugs if any and retest the code.
6. Repeat the cycle until the unit is free of all the bugs.

Unit tests inspect both black boxes or white boxes.
Black Box Test
A black box test (also known as a "functional test") is one in which you feed it inputs and verify the outputs without being able to inspect the internal workings. Furthermore, one doesn't usually have information regarding:
1. how the box handles errors.
2. whether your inputs are executing all code pathways.
3. how to modify your inputs so that all code pathways are executed.
4 The dependencies on other resources.
Black box testing limits your ability to thoroughly test the code, primarily because the you don't know if you're testing all the code pathways. Typically, a black box test only verifies that good inputs result in good outputs (hence the term "functional test").
Classes are often implemented as black boxes, giving the "user" of the class access only to the public methods and properties that the implementer selected.

White box Test:
A white box provides the information necessary to test all the possible pathways. This includes not only correct inputs, but incorrect inputs, so that error handlers can be verified as well. This provides several advantages:
1. You know how the box handles errors
2. You can usually write tests that verify all code pathways
3. The unit test, being more complete, is a kind of documentation guideline that the implementer can use when actually writing the code in the box
4. Resource dependencies are known.
5. Internal workings can be inspected.
In the "write the test first" scenario, the ability to write complete tests is vital information to the person that ultimately implements the code, therefore a good white box unit test must ensure that, at least conceptually, all the different pathways are exercised.
Another benefit of white box testing is the ability for the unit test to inspect the internal state of the box after the test has been run. This can be useful to ensure that internal information is in the correct state, regardless of whether the output was correct. Even though classes are often implemented with many private methods and accessors. with C# and reflection, unit tests can be written which provide you the ability to invoke private methods and set/inspect private properties.

Code Coverage
Although there may be occasional exceptions, we need our tests to cover most of our code. 100% code coverage might be too high a goal to reach for right now, but we need to have a high percentage of the code we right covered in our testing.
There are a number of coverage criteria, the main ones being:
Function coverage - Has each function in the program been executed?
Statement coverage - Has each line of the source code been executed?
Decision coverage (also known as Branch coverage) - Has each control structure (such as an if statement) evaluated both to true and false?
Condition coverage - Has each boolean sub-expression evaluated both to true and false (this does not necessarily imply decision coverage)?
Modified Condition/Decision Coverage (MC/DC) - Has every condition in a decision taken on all possible outcomes at least once? Has each condition been shown to affect that decision outcome independently?
Path coverage - Has every possible route through a given part of the code been executed?
Entry/exit coverage - Has every possible call and return of the function been executed?

NCover is a useful tool for exploring how much of your code is covered by a single test or a suite of tests. It is an open source application, like NUnit.
The Visual Studio Team Test Edition also has a built-in code.

Unit Testing Patterns
Pass/Fail Patterns
The Simple-Test Pattern
The Code-Path Pattern
The Parameter-Range Pattern
Data Driven Test Patterns
The Simple-Test-Data Pattern
The Data-Transformation-Test Pattern
Data Transaction Patterns
The Simple-Data-I/O Pattern
The Constraint-Data Pattern
The Rollback Pattern
Collection Management Patterns
The Collection-Order Pattern
The Enumeration Pattern
The Collection-Constraint Pattern
The Collection-Indexing Pattern
The Performance-Test Pattern
Process Patterns
The Process-Sequence Pattern
The Process-State Pattern
The Process-Rule Pattern
Simulation Patterns
Mock-Object Pattern
The Service-Simulation Pattern
The Bit-Error-Simulation Pattern
The Component-Simulation Pattern
Multithreading Patterns
The Signalled Pattern
The Deadlock-Resolution Pattern
Stress-Test Patterns
The Bulk-Data-Stress-Test Pattern
The Resource-Stress-Test Pattern
The Loading-Test Pattern
Presentation Layer Patterns
The View-State Test Pattern
The Model-State Test Pattern


Code Smells
A code smell is a surface indication that usually corresponds to a deeper problem in the system.

No comments: