Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best approach for breaking dependencies in C#?

We are looking at adding unit tests to our C# code base. I am finding it easy to add unit tests to simple classes, but classes that interact with other dependencies are more difficult. I have been looking at mocking frameworks, but was wondering about the best approach to write classes in the first place to break external dependencies, like file system, database and messaging system dependencies.

To give an example, a routine listens on a socket for a message in a certain format - say MessageA. This is decoded, some calculations are done, this is re-encoded into a different binary format and the resulting message then sent, MessageB.

My current testing approach is as follows. I extract an interface for all socket interactions, and create a mock interface. I set the interface in a singleton. Then run the class against hard coded inputs. The class under test will use the interface in the singleton to send/receive.

I do a similar thing to test database interactions.

This does not seem like the most flexible approach, how would you go about improving this to make it easier to test? If a mocking framework is the answer, how would I design the classes?

Example code :

[SetUp]
public void init()
{
    // set message interface in singleton as mock interface
    CommAdapter.Instance.MessageAdapter = new MockMessage();

    // build reference message from hard coded test variables
    initialiseMessageA();

    // set input from mock message socket
    ((MockMessage) CommAdapter.Instance.MessageAdapter).MessageIn = m_messageA;
}

[Test]
public void test_listenMessage_validOutput()
{
    // initialise test class
    MessageSocket tS = new MessageSocket();

    // read from socket
    tS.listenMessage();

    // extract mock interface from singleton
    MockMessage mm = ((MockMessage) CommAdapter.Instance.MessageAdapter);

    // assert sent message is in correct / correstpoinding format
    Assert.AreEqual(1000001, mm.SentMessageB.TestField);

}
like image 813
C Mars Avatar asked Dec 13 '11 10:12

C Mars


People also ask

Why we should use dependency injection in c#?

Dependency Injection (or inversion) is basically providing the objects that an object needs, instead of having it construct the objects themselves. It is a useful technique that makes testing easier, as it allows you to mock the dependencies.

Why interface is used in dependency injection?

The dependency injection technique. You can introduce interfaces to break the dependencies between higher and lower level classes. If you do that, both classes depend on the interface and no longer on each other.

When should we use dependency injection?

More specifically, dependency injection is effective in these situations: You need to inject configuration data into one or more components. You need to inject the same dependency into multiple components. You need to inject different implementations of the same dependency.

Why is dependency injection important for decoupling code?

Dependency injection is a great way to do that by decoupling our components. It allows us to write cleaner and more concise code that's easier to maintain and refactor.


2 Answers

Instead of using Singletons to set your component implementations, use a Dependency Injection, and a DI library like Ninject. This is exactly the type of scenario they were designed for.

Not pushing you to Ninject specifically, but they have a good tutorial :) The concepts will transfer to other frameworks (like Unity).

  • https://github.com/ninject/ninject/wiki

With DI alone, the code will look something like this:

class Samurai {
  private IWeapon _weapon;
  public Samurai(IWeapon weapon) {
    _weapon = weapon;
  }
  public void Attack(string target) {
    _weapon.Hit(target);
  }
}

class Shuriken : IWeapon {
  public void Hit(string target) {
    Console.WriteLine("Pierced {0}'s armor", target);
  }
}

class Program {
  public static void Main() {
    Samurai warrior1 = new Samurai(new Shuriken());
    Samurai warrior2 = new Samurai(new Sword());
    warrior1.Attack("the evildoers");
    warrior2.Attack("the evildoers");
  }
}

This looks clean now, but wait until your dependencies have dependencies, or further :) You can use a DI library to solve that, though.

With a library to handle the wiring up for you, it will look something like:

class Program {
  public static void Main() {
    using(IKernel kernel = new StandardKernel(new WeaponsModule()))
    {
      var samurai = kernel.Get<Samurai>();
      warrior1.Attack("the evildoers");
    }
  }
}

// Todo: Duplicate class definitions from above...

public class WarriorModule : NinjectModule {
  public override void Load() {
    Bind<IWeapon>().To<Sword>();
    Bind<Samurai>().ToSelf().InSingletonScope();
  }
}

With either of these approaches, plus a mock object framework like Moq, your unit tests look something like this:

[Test]
public void HitShouldBeCalledByAttack()
{
    // Arrange all our data for testing
    const string target = "the evildoers";
    var mock = new Mock<IWeapon>();
    mock.Setup(w => w.Hit(target))
        .AtMostOnce();

    IWeapon mockWeapon = mock.Object;
    var warrior1 = new Samurai(mockWeapon);

    // Act on our code under test
    warrior1.Attack(target);

    // Assert Hit was called
    mock.Verify(w => w.Hit(target));
}

You'll notice you can just pass mock instances straight into the code under test, and you don't have to mess around with setting singletons. This will help you avoid problems like needing to set up the state multiple times, or in between calls. It means no hidden dependencies.

You'll also notice I didn't use the DI container in the tests. If your code is well factored, it will only be testing a single class (and as often as possible, only a single method), and you will only need to mock out the direct dependencies of that class.

like image 186
Merlyn Morgan-Graham Avatar answered Sep 20 '22 13:09

Merlyn Morgan-Graham


In addition to a DI container (I'm using MS Unity 2.0 currently but there are many to choose from) you will need a good mocking framework, my preference is MOQ. A common pattern/process for breaking concrete dependencies is:

  • define the dependency via an interface; you may luck out and already have an interface, like IDbConnection or you may need to use Proxy to wrap a concrete type and define your own interface.
  • resolve the concrete implementation via your DI container
  • inject your mock implementations into your DI container at test setup time (inject real impls. at system startup)
like image 25
Myles McDonnell Avatar answered Sep 16 '22 13:09

Myles McDonnell