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.

Test Driven Development

Test-driven development (TDD) promotes the writing of tests prior to writing the code that is
being tested. This allows you to focus on your interface and what you expect from your code
prior to focusing on its particular implementation.
The testing components for implementing a test-driven development plan are known as unit
tests.
Test-driven software development technique requires that an automated unit test, defining requirements of the code, is written before each aspect of the code itself. These tests contain assertions that are either true or false.
In test-driven development, each feature begins with writing a test, so for each method, the developer should have to write a unit tests related case. Every method will have more than one test case depending on the complexity of the method signature.

Test-driven development gives developers the confidence to make changes to the system,
because they know that the tests will tell them if they have broken anything and where in the
application the break occurred. This is one of the most effective feedback mechanisms that
the development team can have for ensuring stability and high quality.

Another advantage to test-driven development is that it assists in keeping the code simple.
When developers take a code-first approach to development, they have a tendency to
design as they code, without having a clear picture as to what they want to achieve. They
basically let the creative process lead them to a design while they are coding. This often does
not result in the most straightforward solutions. In fact, in many cases, it results in an overly
complicated design. Test-driven development forces developers to think about the outcome of
what they are developing, and then simply code until the test passes, which leads to a simpler
design. This is called development by intention.

Best practices of using TDD:
1. Write the test first, then the code.
Reason: This ensures that you write testable code and that every line of code gets tests written for it.

2. Design classes using dependency injection.
Reason: You cannot mock or test what cannot be seen.

3. Separate UI code from its behavior using Model-View-Controller or Model-View-Presenter. 
Reason: Allows the business logic to be tested while the parts that can't be tested (the UI) is minimized.

4. Do not write static methods or classes.
Reason: Static methods are difficult or impossible to isolate and Rhino Mocks is unable to mock them.

5. Program off interfaces, not classes.
Reason: Interfaces can be easily mocked using Rhino Mocks and other mocking frameworks.
6. Isolate external dependencies. 
Reason: Unresolved external dependencies cannot be tested.


Test-Driven Development is a software development technique consisting of short iterations where new test cases covering the desired improvement or new functionality are written first, then the production code necessary to pass the tests is implemented, and finally the software is refactored to accommodate the changes.
Requires test automation
"Keep It Simple, Stupid" (KISS [^]) principle
"You Ain't Gonna Need It" (YAGNI [^]) principle
"Fake it, till you make it" principle
Requires techniques, such as discussion and code reviews for example, to ensure not only that the correct features are implemented, but that the resulting code uses acceptable styles.

What are three Stages of TDD:
1. Red - Create a test case which is failing.
2. Green - Write minimal code to get the test pass.
3. Refactor - Improve the code to make it better but without changing the behavior. 

TDD Benefits:

1. Clear expectations (clear flow) of the code. 
2. Safety net for future changes
3. Supports continuous integration

Why TDD is more fit in Agile ?
Agile is an iterative development methodology where the term "Continous improvement" very well coined. Agile says that contnous improvement is the goal of the each iteration.