Rationalising mocked dependencies using concrete types

This really is amazingly obvious and simple, but for some reason it never occurred to me.

The situation I’ve been getting myself into is that I have Business Logic actions that do a very discrete bit of logic, these will have dependencies on data access repositories as well as other business logic actions (potentially). I was happily using interfaces for the data access dependencies and then continued to use them for business logic dependencies, this lead to a bit of a mass of interfaces, and I also ended up with tests that mocked all these dependencies, resulting in missing lots of problems that occur in the interaction between business logic actions.

What I really want is that all data access dependencies can be replaced by mocks, but the ‘real’ instances of all the business logic actions are used. This seemed hard to achieve as we are not using an IOC container for our dependency injection (What a pain!) so use a default constructor for each class that just provides real implementations. So if we use a real instance of the business logic dependency we either have to know about it’s dependencies (resulting in massive constructors for all possible dependencies in the object graph).

The solution I hit upon today seems kind of obvious now (and of course is completely irrelevant if you have an IOC Container). Specify all data access dependcies by interface so they can be mocked out. Specify all business logic dependencies as concrete dependencies (still in the constructor). Use default constructors to use default instances of all the dependencies. In tests create all business logic objects for the required object graph using dependency injection, use mocks for data access dependencies and real instances for business logic actions.

Demo class diagram

Demo class diagram

public class Class1
{
  private IDataAccess1 dataAccess1Dependency;
  private Class2 class2Dependency;

  public Class1()
    : this(new DataAccess1(), new Class2())
  { }

  public Class1(IDataAccess1 dataAccess1, Class2 class2)
  {
    this.dataAccess1Dependency = dataAccess1;
    this.class2Dependency = class2;
  }

  public int MethodToTest()
  {
    return class2Dependency.Method() + dataAccess1Dependency.GetInt();
  }
}
public class Class2
{
  private IDataAccess2 dataAccess2Dependency;

  public Class2()
    : this(new DataAccess2())
  { }

  public Class2(IDataAccess2 dataAccess2)
  {
    this.dataAccess2Dependency = dataAccess2;
  }

  public int Method()
  {
    return dataAccess2Dependency.GetInt();
  }
}
/// <summary>
///A test for MethodToTest
///</summary>
[TestMethod()]
public void MethodToTestTest()
{
  MockRepository mocks = new MockRepository();
  IDataAccess1 mockDA1 = mocks.DynamicMock<IDataAccess1>();
  IDataAccess2 mockDA2 = mocks.DynamicMock<IDataAccess2>();
  Class2 class2Instance = new Class2(mockDA2);

  Class1 target = new Class1(mockDA1, class2Instance);
  using (mocks.Record())
  {
    Expect.Call(mockDA1.GetInt()).Return(5);
    Expect.Call(mockDA2.GetInt()).Return(6);
  }
  using (mocks.Playback())
  {
    int expected = 11;//5+6
    int actual = target.MethodToTest();
    Assert.AreEqual(expected, actual);
  }
}
Advertisements

About Alex McMahon

I am a software developer, interested in .net, agile, alt.net. I've previously specialised with .net 3.0 technologies like WCF, whereas now I am trying to specialise in agile development and best practice and patterns. I am obsessed with looking at the latest technologies, tools, and methods, and trying them out. I am currently employed by Rockwell Collins in the UK.
This entry was posted in dependency injection, development, IoC, mocks, MSTest, testing. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s