uncategorized

Code Coverage on Constructor Based Dependency Injection

I was working with nCoverExplorer at work this week checking to see how diligent we’d been while writing our tests.  One of our major tasks in the last month has been to refactor our service layer so that it employs constructor based dependency injection.  When I looked through the coverage on this work I noticed that the coverage was lower than I’d been hoping for.  Closer inspection showed that the culprit was the constructor chaining we were using as part of our Dependency Injection refactoring. 

Below is an example of a class that we would create.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace DependencyInjectionExample
{
public class DIExample
{
private readonly IDependency _dependency1;
private readonly IDependency _dependency2;

public DIExample():this(new SomeDependency(), new AnotherDependency()){}

public DIExample(IDependency dependency1, IDependency dependency2)
{
_dependency1 = dependency1;
_dependency2 = dependency2;
}

public void SomeMethod(string value)
{
_dependency1.DoStuff(value);
_dependency2.DoStuff(value);
}
}
}

And here is an example of how we would test it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using MbUnit.Framework;
using Rhino.Mocks;

namespace DependencyInjectionExample
{
[TestFixture]
public class DIExampleTests
{
private MockRepository _mockery;

[TestFixtureSetUp]
public void Setup()
{
_mockery = new MockRepository();
}

[TestFixtureTearDown]
public void TearDown()
{
_mockery.VerifyAll();
}

[Test]
public void SomeMethod_ShouldCallAppropriateMethods()
{
IDependency mockDependency1 = (IDependency) _mockery.CreateMock(typeof (IDependency));
IDependency mockDependency2 = (IDependency) _mockery.CreateMock(typeof (IDependency));

mockDependency1.DoStuff(string.Empty);
LastCall.IgnoreArguments().Repeat.Once();

mockDependency2.DoStuff(string.Empty);
LastCall.IgnoreArguments().Repeat.Once();

_mockery.ReplayAll();

DIExample diExample = new DIExample(mockDependency1, mockDependency2);
diExample.SomeMethod(string.Empty);
}
}
}

When you run this test through nCover you get this.

ConstructorCoverage

Because my only test, which I believe to be the only one necessary, uses the parameterized override of the constructor, the default constructor does not get executed.  In this example that means that code coverage drops from 100% to 78% which is below the threshold of 90% that I strive for.  I could easily write another test that creates the object using the default constructor, but I don’t see why I’d write that test.  In my mind it doesn’t bring any benefit to the test suite.  I realize that code coverage metric are not metrics of quality and this is why I don’t see the benefit.

My question to all of you is this:  What do you do in this situation?