Wednesday, July 3, 2013

[Visual C#] How to test your applications using the Fakes Framework (2/3)

Now lets start using the Fakes Framework by implementing a real live scenario. In the following example I am going to show you some legacy code, which has some software design flaws. I am going to apply TDD and SOLID concepts to improve code quality and then use Fakes Framework Stubs for testing it.

Then in the next blog post of the series I am going to show you how to test source code without any code modifications by using Fakes Framework Shims. This is especially interesting for code that cannot be modified or that requires too many modifications and which is thus too expensive to improve.

Refactoring badly designed source code

The BusinessService class has the responsibility to store Deals in the database if they are valid :

image

As you see it uses two other business classes : the DealValidator class for deal validation and the DealRepository class for saving a deal to the database. If a deal is not valid an exception is thrown. Furthermore, a bool with the False value is returned, if a deal cannot be saved to the database.

Here are the implementations of the classes, without any actual source code. The methods only contain a not implemented exception. We are going to mock those objects later, so no need to implement them completely here. Even more, by doing it like this, we have the opportunity to validate that they are not actually called. We do not want to have them called, when we unit test the BusinessService class, since they are part of its external dependencies (as explained in the first part of the blog series).

image

The Deal class is a simple data transfer object (DTO) :

image

Lets analyze the software design of this simple example : the BusinessService class and the DealValidator, DealRepository and Deal classes are tightly coupled as it is implemented here. This is bad design and a violation of the SOLID principles. To be more specific it violates the Dependency Inversion Principle (DIP).

The first thing to do now, is to modify the code to make it adhere to the DIP principle and thus improving its quality. When applying TDD and writing unit tests, you have to isolate the code that has to be tested (System Under Test). So if we want to unit test all the methods of the class, we have to decouple its methods from the rest of the source code. In the end the DIP principle gets automatically respected.

To achieve this goal we are going to do some dependency injection. First we use Interfaces to serve as abstraction layer between the BusinessService class and the DealValidator, DealRepository and Deal classes :

image

The business classes and interfaces code looks now like this :

image

You are now ready to use the Fakes Framework to test your code. This is what we are going to do in the next step.

Fakes Framework Stubs

Now that the BusinessService class has been completely decoupled, we can use Fakes Framework Stubs for unit testing it. After creation of a new unit test project and after adding a reference to our business code project, we generate the Fakes Framework library by right-clicking on the reference and selecting “Add Fakes Assembly”.

image

Visual Studio 2012 automatically adds the following to the project :

image

  1. A library called CodeSample.Fakes, which contains the auto-generated Stubs and Shims classes. Those are going to be used as proxies in our unit tests.
  2. A reference to Microsoft.QualityTools.Testiong.fakes.dll, which contains all the core components of the Fakes Framework.
  3. A Fakes folder, that contains a file called xml CodeSample.fakes. This file allows to impact the automatic generation of Stubs and Shims.

For our example we declare that Stubs have only to be generated for Interfaces :

image

We may now implement unit tests using the Stubs that were auto-generated above in the CodeSample.Fakes.dll.

The following unit test will return True when the TrySave(…) method is called and a deal has been validated and saved (which is the case in our example) :

image

Lets see how that works in  detail : in the Setup step we initialize the IRepository and IValidator interfaces by using the corresponding Stubs. Note that the classname is “Stub” and then the name of the interface to substitute.

Then we simulate a save and validation operation that has been  successfully finished. To do that we define that the Save(…) and IsValid(…)  methods return always True.

In terms of naming conventions, methods are suffixed by the type name of their input parameters. In our example the IsValid(…) and Save(…) methods have both as input parameter IDataObjet, so they are named IsValidIDataObject(…) and SaveIDataObject(…).

Finally, we use the Stubs from above to instantiate a BusinessService object (also doing some constructor injection) and we test the TrySave(…) method to validate that the result is conform with our scenario.

In the next example, we test that the TrySave(…) methods calls a validator :

image

To achieve this, we are using the variable validatorWasCalled, which we initialize to the False value. The test is validating that the variable is set to True during the processing in the corresponding Stub when calling the TrySave(…) method.


Share/Save/Bookmark

No comments: