Code Refactoring and Dependency Injection C#
-
I have UI call to the businesslayer as,
BusinessEntity.WorkQueueBE be = BusinessLayer.WorkQueueBEManager.GetItemByID(wqID);
In the business layer, WorkQueueBEManager class, method is defined as,
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static WorkQueueBE GetItemByID(int id)
{
return DataAccess.WorkQueueDB.GetItemByID(id);
}In the data access layer, stored proc is called, it fills the WorkQueueBE object and returns the result. I need to write unit tests for this legacy code. I reckon i need to do some refactoring to introduce unit testing here. Can someone please suggest how to move ahead, so that i can make the code loosely coupled.
-
I have UI call to the businesslayer as,
BusinessEntity.WorkQueueBE be = BusinessLayer.WorkQueueBEManager.GetItemByID(wqID);
In the business layer, WorkQueueBEManager class, method is defined as,
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static WorkQueueBE GetItemByID(int id)
{
return DataAccess.WorkQueueDB.GetItemByID(id);
}In the data access layer, stored proc is called, it fills the WorkQueueBE object and returns the result. I need to write unit tests for this legacy code. I reckon i need to do some refactoring to introduce unit testing here. Can someone please suggest how to move ahead, so that i can make the code loosely coupled.
Your code isn't really unit-testable as it stands. If you look at Microsoft Fakes you might be able to use that to mock your business layer as that can even mock static objects. If you want to do it "properly" then you'll need your BusinessLayer object to implement an interface (IBusinessLayer) and use inversion of control to pass an instance of your BusinessLayer or WorkQueueBEManager to your calling class. Rather than calling BusinessLayer.WorkQueueBEManager.GetItemByID(wqID) as you are now, you'll call the instance
BusinessEntity.WorkQueueBE be = this.businessLayer.WorkQueueBEManager.GetItemByID(wqID);
(where this.businessLayer is IBusinessLayer and populated via IoC) In your unit tests you then pass in a mocked version of BusinessLayer. If you google unit testing asp.net code you should find some specific examples of this stuff.
-
Your code isn't really unit-testable as it stands. If you look at Microsoft Fakes you might be able to use that to mock your business layer as that can even mock static objects. If you want to do it "properly" then you'll need your BusinessLayer object to implement an interface (IBusinessLayer) and use inversion of control to pass an instance of your BusinessLayer or WorkQueueBEManager to your calling class. Rather than calling BusinessLayer.WorkQueueBEManager.GetItemByID(wqID) as you are now, you'll call the instance
BusinessEntity.WorkQueueBE be = this.businessLayer.WorkQueueBEManager.GetItemByID(wqID);
(where this.businessLayer is IBusinessLayer and populated via IoC) In your unit tests you then pass in a mocked version of BusinessLayer. If you google unit testing asp.net code you should find some specific examples of this stuff.
For now, to start the refactoring and unit testing, important part is to separate Data access layer from business layer. As you can see,
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static WorkQueueBE GetItemByID(int id)
{
return WorkQueueDB.GetItemByID(id);
}the code directly calls the dataaccess layer. This makes it untestable. What i want to acheieve is to start testing these methods, and create mock for data access layer so that it can return hardcoded values while testing. But how do i proceed with that ? Create interface, implement them in data access layer ? If anyone can cite an example on how to implement it.
-
I have UI call to the businesslayer as,
BusinessEntity.WorkQueueBE be = BusinessLayer.WorkQueueBEManager.GetItemByID(wqID);
In the business layer, WorkQueueBEManager class, method is defined as,
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static WorkQueueBE GetItemByID(int id)
{
return DataAccess.WorkQueueDB.GetItemByID(id);
}In the data access layer, stored proc is called, it fills the WorkQueueBE object and returns the result. I need to write unit tests for this legacy code. I reckon i need to do some refactoring to introduce unit testing here. Can someone please suggest how to move ahead, so that i can make the code loosely coupled.
Assuming DataAccess is a static class, you are in for a bit of work. I can think of several approaches, all of them boiling down to some form of dependency injection without going as far as trying to shoehorn an IoC container into your existing code. One approach that could work: 1. Create an IDataAccess interface. Give it all the methods your DataAccess class currently has to provide your business entities with their data. 2. Remove the static specifier from your DataAccess class and make it an implementer of the new IDataAccess interface. 3. Create a new static class, for example DataAccessLayer and give it a single method, for example: Current(). Implement that method to return an instance of the DataAccess class as an IDataAccess interface reference. It is up to you to create a new instance for every call or to create a single instance and return that all the time. 4. Give every business entity a property of type IDataAccess. (They do all derive from some base class I hope?) Name it DataAccess. As it is closer in scope than anything outside of your business entities any method in those entities referencing DataAccess should now use the interface property instead of the DataAccess class. 5. Implement the DataAccess property getter of your business entities in such a way that it can returns the DataAccessLayer.Current IDataAccess interface reference, UNLESS a private IDataAccess _DataAccess member is non-null. In that case return the member reference. 6. Give all your business entities an extra "InitalizeDataAccess" method taking an IDataAccess parameter. Implement it to assign whatever is passed in to the private _DataAccess member. 7. Use the InitializeDataAccess method in your tests to provide your business entities with an IDataAccess implementer (DataAccess fake) that provides the business entities with data as needed by your tests.