Introduction
This article would discuss how to use Unity Application Block for unit testing. Unity Application Block provides a dependency injection container. It is available as part of Microsoft Enterprise Library and separately as well. It can be downloaded from here.
Background
Unit testing most commonly needs a test program and mock objects / stubs. Test program would be the test projects provided by Visual Studio. Now, one does not need to write code for creating Unit under test and initialize it with respective mock or stubs to be able to do testing in isolation. This can be accomplished through Unity and one can just concentrate on writing better tests for the unit under test.
Unit Testing
Automating unit testing allows developers and testers a better and quick way to test their code for logical errors. Once created, running these tests as the code changes and adding more tests makes sure that the developer working on it has not introduced any defects.
Following are some of these guidelines to keep in mind while writing unit tests:
- Single Condition Tests.
- Test concerns separately, for example, there should be separate tests for Business and Data access layers.
- Minimize test overlap.
- Defect Localization, keeping unit tests small, in case of a defect, it will be easy to locate it based on the failing test.
- Keep Tests Independent, Fresh Fixture strategy would help.
- Self checking Tests, using Built-in/Custom Assertions.
- Purpose of the test should be very clear.
- Minimize un-testable code.
- Keep test logic out of production.
- Tests should be repeatable.
- Write the unit test first. This is optional depending on if test-driven development or test-first development is used.
Also, some of the guidelines and patterns for organizing unit test such as Testcase
class per Feature, Testcase
class per Fixture can be considered.
Unity Application Block
Unity Application Block provides a dependency injection container. Dependency Injection is a pattern allowing loose coupling on the principle of separating behavior from dependency resolution. Unity is a lightweight and extensible dependency injection container that supports injection through constructor, property and method call. It can help in de-coupling, simplifying design and testing of the application.
Design
Layered architecture simplifies automated testing, as simple as 3-Tier architecture would do. In the above diagram, I have shown ICustomerFacade, ICustomerManager
implemented by CustomerFacade, CustomerManager
components respectively. This is Interface-based programming; interfaces provide contract or specification for implementation, all the classes implementation should conform to the contract. We need to have interface at each component. In terms of dependency injection, a dependent consumer.
Using the Code
Before we start on the steps for creating and configuring unity, it’s required to have Enterprise Library 5.0 or Microsoft Unity 2.0 installed.
To begin with, we take an example of the business facade class CustomerFacade
, this is how it looks:
public class CustomerFacade : ICustomerFacade
{
[Dependency]
public ICustomerManager CustomerManager { get; set; }
#region ICustomerFacade Members
public long CreateCustomer(Customer customer)
{
try
{
return CustomerManager.CreateCustomer(customer);
}
catch (Exception e)
{
throw new BusinessException("BusinessException Occurred", e);
}
}
#endregion
}
For the sake of simplicity, I have taken a vanilla example.
The properties to be resolved using unity should be marked with DependencyAttribute
. In the above code, CustomerManager
property has this attribute.
CustomerFacade
implements interface ICustomerFacade
, there by separating behavior from dependency:
public interface ICustomerFacade
{
long CreateCustomer(Customer customer);
}
Now, we will see how we can test CustomerFacade
with the help of Unity Application block:
Step 1: Create Test project and add references
- Add a test project to the solution in Visual Studio.
- Add references to
Microsoft.Practices.Unity
, Microsoft.Practices.Unity.Configuration
, System.Configuration
.
Step 2: Add Test class
- Add a test class to the test project created in Step 1.
- Import namespaces
.Practices.Unity
, Microsoft.Practices.Unity.Configuration
, System.Configuration
.
Step 1 and Step 2 can be automated using Visual Studio 2008 Professional
- Right click on the method and choose Create Unit Tests…
- In the dialog box, select the methods to be included for automatic
Test
class and method generation. - Select an Existing or New Test project
- Click Ok
Step 3: Add an App.config file to the test project created in Step 1.
Step 4: Setup the Unity Configuration part of the App.config file created in Step 3:
="1.0"="utf-8"
<configuration>
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"
<assembly name="UnitTestingWithUnity" />
<assembly name="UnitTestingWithUnity.Test" />
<namespace name="UnitTestingWithUnity.BusinessFacade" />
<namespace name="UnitTestingWithUnity.Business" />
<namespace name="UnitTestingWithUnity.Data" />
<namespace name="UnitTestingWithUnity.Test.Mock" />
<container>
<register type="ICustomerManager" mapTo="MockCustomerManager" />
<register type="ICustomerDataAccess" mapTo="MockCustomerDataAccess" />
</container>
</unity>
</configuration>
Understanding the configuration file:
- Add the
UnityConfigurationSection
reference to your configuration file. - Add all the assembly and namespaces required to resolve the interface and the implementation classes in the configuration.
MockCustomerManager
class implements interface ICustomerManager
. - Register the interfaces to be resolved using the container with the respective map to class.
Step 5: Writing your test:
TestInitilize
method should initialize the unity container to load the unity configuration created in the previous step.
private IunityContainer unityContainer;
[TestInitialize()]
public void MyTestInitialize()
{
unityContainer = new UnityContainer();
unityContainer.LoadConfiguration();
}
Unity container can be initialized without using the configuration files as well. Instead of LoadConfiguration
, we should use RegisterType
method on unity container.
unityContainer.RegisterType<ICustomerManager, CustomerManager >();
unityContainer.RegisterType<ICustomerDataAccess, CustomerDataAccess>();
In the test method, we will use the unity container we just created to resolve the CustomerFacade
class.
[TestMethod()]
public void CreateCustomerTest2()
{
ICustomerFacade target = new CustomerFacade();
target = unityContainer.BuildUp<ICustomerFacade>(target);
Customer customer = new Customer{Name="Test 1", Address = "Test Address 1" };
long custId = target.CreateCustomer(customer);Assert.AreEqual(custId, 1);
}
For Unity to resolve all the dependencies, we should use the dependency injection container provided by Unity to construct and initialize objects. It can be done in 2 ways:
Create the object with new operator, and then use BuildUp
method on unity container to resolve all the dependencies:
ICustomerFacade target = new CustomerFacade();
target = unityContainer.BuildUp<ICustomerFacade>(target);
Alternatively, use Resolve
generic method to create and resolve dependencies in one go:
ICustomerFacade target = unityContainer.Resolve<CustomerFacade>();
Step 6: Execute the Test just created.
That’s about it.
References
History
- 12th February, 2011: Initial post