This example shows legacy console application, which source code contains no tests and is not testable. It is hard to maintain or extend. We will use refactoring techniques to make it testable using TDD principles. We will result in well tested code and structured OOP code, which is easy to modify. It is strongly recommended to have a look at repository history, how the solution was created.
This code was inspired by following video: http://channel9.msdn.com/blogs/mtaulty/prism--silverlight-part-1-taking-sketched-code-towards-unity
Notes:
- First refactoring is critical, we don’t have tests yet
- Allow access internal members by adding InternalsVisibleTo(„Tests“)
- Extract only necessary code to internal static methods
- Best practice is to avoid „public static“ (e.g. SingleTon, Service locator)
- Validate „Test Coverage“ (e.g. using JetBrains dotCover) after each change
- Add Tests project
- Add InternalsVisible to the Calculator project and add reference to the Tests project
- Use Extract method refactoring to made the the Add method test able
- Added test to fix the add method and fix the method
- Use Extract class refactoring to move Add method from Program class to Mathematics class
- Move the Console.WriteLine out of the switch statement (to local variable, split declaration and assingment and move variable to outer scope refactorings)
- Use extact method to isolate the switch statement to calculate method and update tests
- Refactor the Calculate method to simplify the code
- Moved Calculate method to new CalculatorService class using extract class refactoring
- Added new failing test for new substract operation
- Implemented Sub command
- Extract the console interaction to separate methods (extract method refactoring)
- Extract the UI methods to separate class (exctract class refactoring)
- Change the Console UI methods from static to instance methods
- Extract Calculate method from Main by consuming Console UI
- Extract IUserInterface from ConsoleUserInterface class
- test the Calculate method in program class
- Move the calculate method from Program class to calculator service (now you are able to use any other Phone, desktop or web UI to use the same CalculatorService engine)