3

I have a C# class which instantiates on its own a NetworkCommunicator class. I'd like to mock out the NetworkCommunicator class for my unit test, and replace it with a pretty simple stub.

But the NetworkCommunicator is never passed as a parameter. It's created by the class being tested.

In Ruby, this is easy to mock out. In Java, this is why you need Dependency Injection, which is too heavy for this project. Is there a simple way to mock this out in C#, perhaps using Moq or something similar?

k.m
  • 30,794
  • 10
  • 62
  • 86
SRobertJames
  • 8,210
  • 14
  • 60
  • 107

5 Answers5

5

You mentioned that DI is too heavyweight for this project, why not try some Truck Driver's DI, thus:

public interface IDependency
{
    void DoSomeStuff();
}

public class ClassUnderTest
{
    private IDependency _dependency;

    public ClassUnderTest(IDependency dependency)
    {
        _dependency = dependency;
    }

    public ClassUnderTest() : this(new Dependency())
    {}

    public void ImportantStuff()
    {
        _dependency.DoSomeStuff();
    }
}

Using this constructor chaining technique, you can now mock the IDependency all you want, without worrying about hooking up DI or IoC.

Greg Smith
  • 2,449
  • 2
  • 24
  • 37
  • It's possible to use a constructor shim, that enables mocking of an internally new'ed class :-) – Christoffer Dec 31 '12 at 00:24
  • Aye ok - there are a few ways to do it, but I personally say trying to mock an internal is a bad idea when DI is so easy... – Greg Smith Dec 31 '12 at 00:27
  • This approach is called [bastard injection](http://stackoverflow.com/questions/7099406) (a.k.a. poor man's DI). Although considered an anti-pattern, I would also advise starting with it in this case (so +1 for the answer). Dependency injection is absolutely **not** too heavy for any project. The use of a DI framework on the other hand might be 'too heavy' for the project. – Steven Dec 31 '12 at 12:51
4

Create a "TestClass" that inherits from your class under test. Override that parameter with a mocked instance Create a property on the class under test that returns the new instance

public class ClassUnderTest {

public string MethodYouAreTesting(int someInput) {

var networkCommunicator = GetNetworkCommunicator();
// Do some stuff that I might want to test
return "foo";

}

public virtual NetworkCommunicator GetNetworkCommunicator {
    return new NetworkCommunicator();
}

}

[TestFixture]
public class ClassUnderTestTests {
public void GivenSomeCondition_MethodYouAreTesting_ReturnsFooString() {

var classToTest = new TestClassUnderTest();
var result = classToTest.MethodYouAreTesting(1);
Assert.That(result, Is.EqualTo("foo");

}
}

public class TestClassUnderTest : ClassUnderTest {

public override GetNetworkCommunicator {
return MockedNetworkCommunicator;
}

}

I read of this technique this in the "Art of Unit Testing" and use it frequently when refactoring to full DI doesn't make sense or when the class I'm testing isn't something I can change.

Hope this helps.

coach_rob
  • 877
  • 13
  • 28
3

You should refactor your code and pass dependencies in. You can also use typemock as easier to use alternative to fakes in Visual Studio 2012.

LeffeBrune
  • 3,441
  • 1
  • 23
  • 36
  • 1
    +1 for refactor code; if your classes are hard to test then make them easier to test – Christoffer Dec 31 '12 at 00:26
  • @Steven, sometimes refactoring effort is too expensive for large legacy project and teams have no other choice but use tools like typemock of fakes framework. – LeffeBrune Dec 31 '12 at 13:22
1

There's the built-in Fakes system, pretty well described at http://msdn.microsoft.com/en-us/library/hh549175.aspx

If that is too heavy-weight for your use case you might find the PrivateObject class more useful.

Christoffer
  • 12,712
  • 7
  • 37
  • 53
1

I have a C# class which instantiates on its own a NetworkCommunicator class.

As you noticed, this is a show stopper in C# when you want to mock this thing out. Solution is simple, and depends on context/purpose of the instantiated class:

  • inject it as a dependency if it's reusable component
  • provide it via factory if it's something that should be created every time when demand comes in

Either way, you'll need DI (factory from the second example is naturally injected too).

In Java, this is why you need Dependency Injection, which is too heavy for this project.

Is dependency injection too heavy? DI is design pattern, it's only too heavy when used when it's not really needed. Your question clearly shows you need it. Perhaps you meant that DI container is too heavy for your project? This might be true, as depending on project's complexity, you should choose appropriate way to apply DI.

I'd like to raise one more point to be aware of when applying solution like the one proposed in Greg Smith's answer. Essentially, your API ends up with constructors:

public TestedClass() : this(new Dependency()) ...
public TestedClass(IDependency) ...

As appealing as it might be at first glance, when long-term perspective is taken into account, several issues start to emerge:

  • does TestedClass must have IDependency or can it do fine without it?
  • what default (parameterless constructor) defaults to (implementation detail-level knowledge is required to use it properly)?
  • it creates tightly coupled components (TestedClass assembly will possibly have to reference other assembly - Dependency's assembly, even though it might not be relevant to it anyhow)

This is an anti-pattern going under different names, e.g. Bastard Injection. Of course, some of those problems might be mitigated (like making constructor protected/internal or having default implementation in the same assembly), but the anti-pattern and its long-term consequences remain. Also note that it's by no means more simple, faster or less code than regular DI.

You'll have to ask yourself what's less heavy - applying proper DI, or going you ways around with anti-patterns and/or 3rd party frameworks (MS Fakes).

Community
  • 1
  • 1
k.m
  • 30,794
  • 10
  • 62
  • 86
  • You just nailed it. This is THE answer to this question. I hope this will be accepted as answer. – Steven Dec 31 '12 at 12:55
  • I agree that in cases where there is any degree of complexity, my suggestion isn't the way to go, but in this case, the requirement seems to be to get a class testable quickly and cheaply, in which case poor man's injection is, in my personal opinion, usually fine. – Greg Smith Dec 31 '12 at 14:36