This is the latest and greatest bug tracking software and we need to add a feature – send an email when a bug with certain severity is created.The code we want to test looks something (read: exactly) like this:
public class BugTracker
{
private readonly IBugRepository _repository;
private readonly IEmailClient _emailClient;
public BugTracker(IBugRepository repository, IEmailClient emailClient)
{
_repository = repository;
_emailClient = emailClient;
}
public Bug CreatNewBug(string title, Severity severity)
{
if (string.IsNullOrEmpty(title))
{
throw new ApplicationException("Title cannot be empty");
}
var newBug = new Bug
{
Title = title,
Severity = severity
};
SaveBugToDb(newBug);
// Here be code
return newBug;
}
[TestFixture]
public class BugTrackerTests
{
[Test]
public void CreatNewBug_CreateBugHasHighestSeverity_SendEmailToProjectManager()
{
}
}
[Test]
public void CreatNewBug_CreateBugHasHighestSeverity_SendEmailToProjectManager()
{
var cut = new BugTracker();
cut.CreatNewBug("my title", Severity.OhMyGod);
}
Unfortunately this does not even compile. The problem is that I need to “feed” the BugTracker class two dependencies of type IBugRepository and IEmailClient – so let’s add them courtesy of an Isolation framework (in this case FakeItEasy):[Test]
public void CreatNewBug_CreateBugHasHighestSeverity_SendEmailToProjectManager()
{
var fakeBugRepository = A.Fake<IBugRepository>();
var fakeEmailClient = A.Fake<IEmailClient>();
var cut = new BugTracker(fakeBugRepository, fakeEmailClient);
cut.CreatNewBug("my title", Severity.OhMyGod);
}
And now we can write the actual assertion.[Test]
public void CreatNewBug_CreateBugHasHighestSeverity_SendEmailToProjectManager()
{
var fakeBugRepository = A.Fake<IBugRepository>();
var fakeEmailClient = A.Fake<IEmailClient>();
var cut = new BugTracker(fakeBugRepository, fakeEmailClient);
cut.CreatNewBug("my title", Severity.OhMyGod);
A.CallTo(() => fakeEmailClient.Send("manager@project.com", "Don't Panic!")).MustHaveHappened();
}
private void SaveBugToDb(Bug newBug)
{
if (!_repository.Connected)
{
throw new ApplicationException("Cannot access bug repository");
}
_repository.Save(newBug);
}
This means going back to the drawing board for us.[Test]
public void CreatNewBug_CreateBugHasHighestSeverity_SendEmailToProjectManager()
{
var fakeBugRepository = A.Fake<IBugRepository>();
A.CallTo(() => fakeBugRepository.Connected).Returns(true);
var fakeEmailClient = A.Fake<IEmailClient>();
var cut = new BugTracker(fakeBugRepository, fakeEmailClient);
cut.CreatNewBug("my title", Severity.OhMyGod);
A.CallTo(() => fakeEmailClient.Send("manager@project.com", "Don't Panic!")).MustHaveHappened();
}
public Bug CreatNewBug(string title, Severity severity)
{
if (string.IsNullOrEmpty(title))
{
throw new ApplicationException("Title cannot be empty");
}
var newBug = new Bug
{
Title = title,
Severity = severity
};
SaveBugToDb(newBug);
if (severity == Severity.OhMyGod)
{
_emailClient.Send("manager@project.com", "Don't Panic!");
}
return newBug;
}
Labels: .NET, C#, FakeItEasy, Mock objects, NUnit, TDD, Tips and Tricks, Unit tests