Click here to Skip to main content
15,885,032 members
Articles / Programming Languages / C#

Constructing the SUT (System Under Test) – Eradicating Brittle Unit Tests

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
19 Apr 2015CPOL3 min read 13.6K   5   3
How to construct the SUT (System Under Test) – Eradicate Brittle Unit Tests

Introduction

I’m not going to proselytize unit testing in this blog post, there are hoards of articles on the internet for that already. Let’s just agree, for arguments sake, that they do awesome things for any software project. In spite of this majesty, brittle unit tests can suck the life out of programmers. There are many reasons for test frailty (a topic for another time), but the main one I’m going after in this piece is adding dependencies. In short, adding a new dependency to any class makes the existing tests fail. Is there any way of getting around this? Yes, there is!

As a side note: In a perfect world, software would be architected so elegantly that adding dependencies would be unnecessary. Unfortunately, I don’t live in that world. If you know how to get there, please send me directions! That being said, adding dependencies may be a sign that you aren’t adhering to the single responsibility principal. Just something to keep in mind… Regardless, the pattern laid out below has made my life easier.

The Developer and the Brittle Test

Once upon a time, in a land far far away, our hero writes the following really interesting service.

C#
public class ReallyInterstingService
{
    private readonly IDoSomethingAwesome _doSomethingAwesome;
    public ReallyInterstingService(IDoSomethingAwesome doSomethingAwesome)
    {
        this._doSomethingAwesome = doSomethingAwesome;
    }
    public string InterstingMethod()
    {
        return this._doSomethingAwesome.ToString();
    }
}

This really interesting service needs tests. Our hero, being a true hero, used TDD so he wrote the tests below before ever writing the service. Problem solved!

C#
[TestClass] public class ReallyInterstingServiceShould 
{ 
    [TestMethod] public void ReturnString() 
    {   
        var awesomeMock = new Mock<IDoSomethingAwesome>(); 
        var sut = new ReallyInterstingService(awesomeMock.Object); 
        var result = sut.InterstingMethod(); 
        Assert.IsInstanceOfType(result, typeof(string)); 
    } 
}

The tests are fantastic! Anyone can refractor without fear. Life is good! However, as with any great story, along comes the antagonist: the evil manager. Management demands our hero to befoul really interesting service with some inanity. After a long battle, our hero concedes and makes the modifications below.

C#
public class ReallyInterstingService 
{ 
    private readonly IDoSomethingAwesome _doSomethingAwesome; 
    private readonly IDeathToAwesome _deathToAwesome; 
    public ReallyInterstingService(IDoSomethingAwesome doSomethingAwesome, 
					IDeathToAwesome deathToAwesome) 
    { 
        this._doSomethingAwesome = doSomethingAwesome; 
        this._deathToAwesome = deathToAwesome; 
    } 
    public string InterstingMethod() 
    { 
        return this._doSomethingAwesome.ToString(); 
    } 
    public string LoadOfTripe() 
    { 
        return this._deathToAwesome.ToString(); 
    } 
}

As you can see, a new dependency was added and now all the beautiful tests have failed. Woe to the kingdom. Our hero is vexed! How could he have foreseen this tragedy? What can he do to protect the program against such calamity in the future?

After a long quest, our hero stumbles upon the humble author’s DotNetTestHelper open source project. It’s an incredibly simple library still in its infancy, but it has something wonderful: SutBuilder! He refractors the test as follows:

C#
[TestClass] public class ReallyInterstingServiceShould 
{ 
    [TestMethod] public void ReturnString() 
    { 
        var awesomeMock = new Mock<IDoSomethingAwesome>(); 
        var sut = new SutBuilder<ReallyInterstingService>() .AddDependency(awesomeMock.Object) .Build(); 
        var result = sut.InterstingMethod(); Assert.IsNotNull(result); 
        Assert.IsInstanceOfType(result, typeof(string)); 
    } 
}

What wizardry is this, say you? The SUT was constructed without the added dependency! The test is also protected against added dependencies in the future. The kingdom is saved! They lived happily ever after.

The End

Ok Ok Ok, that was a bit absurd. Anyway…

SutBuilder is a utility I wrote as part of an open source project of .NET testing utilities. The full source code is available here. What it does is simple: it constructs an instance of the generic type parameter. See the code below.

These two statements have identical results:

C#
sut = new ReallyInterstingService( new Mock<IDoSomethingAwesome>().Object, 
	new Mock<IDeathToAwesome>().Object); 
sut = new SutBuilder<ReallyInterstingService>().Build();

Note: I’m using Moq to create mocks. I really dig that framework! It’s free and easy to use.

SutBuilder finds the constructor with the most arguments and uses it for instantiation. For each constructor argument, SutBuilder determines if an object of the argument type was passed in via the AddDependency method. If it was, it will pass that object to the constructor, otherwise it will pass an empty Moq mock of that type. AddDependency returns an instance of SutBuilder to provide a nice fluent API. See the code below.

C#
IDoSomethingAwesome somethingAwesome = new DoSomethingAwesome(); 
// These two statements have identical results 
sut = new ReallyInterstingService( somethingAwesome, new Mock<IDeathToAwesome>().Object); 
sut = new SutBuilder<ReallyInterstingService>().AddDependency(somethingAwesome).Build();

All the magic happens in the Build method where it returns the created instance. That’s all there is to it!

As mentioned above, DotNetTestHelper is in its infancy. I will entertain any and all pull requests!

Thank you for reading!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
I’m a passionate developer with more than 20 years of experience in countless different languages. Currently, I’m a senior software engineer for a research company where I specialize in full stack web development with .NET. I have extensive experience with ASP.NET, MVC, C#, Azure, JavaScript, JQuery, AngluarJS, TypeScript, NoSQL (RavenDB), and SQL Server.

Comments and Discussions

 
QuestionNuget Pin
Hideous Humpback Freak20-Apr-15 14:49
Hideous Humpback Freak20-Apr-15 14:49 
GeneralMy vote of 5 Pin
Attila Kúr20-Apr-15 9:36
Attila Kúr20-Apr-15 9:36 
GeneralRe: My vote of 5 Pin
Hideous Humpback Freak20-Apr-15 14:48
Hideous Humpback Freak20-Apr-15 14:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.