views:

222

answers:

3

I am new to mocking and dependency injection and need some guidance.

My application is using a typical N-Tier architecture where the BLL references the DAL, and the UI references the BLL but not the DAL. Pretty straight forward.

Lets say, for example, I have the following classes:

class MyDataAccess : IMyDataAccess {} class MyBusinessLogic {}

Each exists in a separate assembly.

I want to mock MyDataAccess in the tests for MyBusinessLogic. So I added a constructor to the MyBusinessLogic class to take an IMyDataAccess parameter for the dependency injection. But now when I try to create an instance of MyBusinessLogic on the UI layer it requires a reference to the DAL.

I thought I could define a default constructor on MyBusinessLogic to set a default IMyDataAccess implementation, but not only does this seem like a codesmell it didn't actually solve the problem. I'd still have a public constructor with IMyDataAccess in the signature. So the UI layer still requires a reference to the DAL in order to compile.

One possible solution I am toying with is to create an internal constructor for MyBusinessLogic with the IMyDataAccess parameter. Then I can use an Accessor from the test project to call the constructor. But there's still that smell.

What is the common solution here. I must just be doing something wrong. How could I improve the architecture?

+2  A: 

I answered a question yesterday on how to structure a .NET solution that I think will solve your problem.

The key point for you in my answer should be that none of the "implementation" assemblies have references to other "implementation" assemblies. This should solve you separation of concerns issue.

Further, the structure also almost mandates the use of dependency injection and it is very well suited for unit testing and the use of mocking.

I hope it helps.

Enigmativity
This sounds like a really great solution, but I think it would be quite an up-hill struggle to convince the rest of my team to restructure our entire application.
whatispunk
A: 

If you want to avoid having to reference the data access dll from the UI dll, then you could extract the data access interfaces/base classes into a third library and have both the other two reference that.

Lee
+4  A: 

You can define your classes like this:

public class MainForm : Form
{
    private readonly businessLogic;

    public MainForm(IBusinessLogic businessLogic)
    {
        this.businessLogic = businessLogic;
    }
}

public class BusinessLogic : IBusinessLogic
{
    private IDataLayer dataLayer;

    public BusinessLogic(IDataLayer dataLayer)
    {
        this.dataLayer = dataLayer;
    }
}

public class DataLayer : IDataLayer
{
    public DataLayer(string connectionString)
    {
    }
}

Note how the main form doesn't know about the DAL here. Now we do need a piece of code which knows all the classes, so that they can be wired together. This is typically done at the start of the application:

public static void Main(string[] args)
{
   var dataLayer = new DataLayer("foo");
   var businessLogic = new BusinessLogic(dataLayer);
   var mainForm = new MainForm(businessLogic);

   Application.Run(mainForm);
}

Of course, this is a simplified example. If you have dozens or hundreds of classes in practice, then such start-up wiring can get very big and complicated, especially when cyclic dependencies come into play. That's why dependency injection frameworks were created to replace that code by XML configuration files, configuration by code, or .NET attributes. The basic idea is the same though.

Examples of dependency injection frameworks for .NET: AutoFac, Castle, Spring.NET, StructureMap, Ninject and the Managed Extensibility Framework.

Wim Coenen
How does using an IoC container affect performance? I like this solution a lot and am currently playing around with Castle.
whatispunk
@whatispunk: Using an IoC container doesn't have an impact on performance after start-up. If start-up times get too long because of the amount of objects being wired together, you typically have facilities in the container to enable lazy loading (e.g. `System.Lazy<T>` for the managed extensibility framework).
Wim Coenen
Makes sense. And in my case, I'm working on a Web app, so start-up times don't really matter. Thanks for your help.
whatispunk