Here's a structure for unit tests I've been using for a little bit. It's based off an a SpecificationBase class I found from I think Jimmy Bogard on LosTechies.
The nice thing here is each scenario is encapsulated into it's own class. And then you read the tests it sounds natural.
This assumes NUnit and FakeItEasy are being used, but it could modified for MS-TEST.
[TestFixture]
public abstract class SpecificationBase
{
[SetUp]
public void SetUp()
{
Given();
When();
}
protected virtual void Given() { }
protected virtual void When() { }
}
public class ThenAttribute : TestAttribute { }
Then here's the actual contoller tests
public static class DataControllerTests
{
public class WhenViewingWesternRegionLoadLookAhead : SpecificationBase
{
private DataController _sut;
private ViewResult _result;
private IProvideeDataFeedData _eDataProvider;
protected override void Given()
{
_eDataProvider = A.Fake<IProvideeDataFeedData>();
A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).Returns(new collectionActualValueData
{
timestamp = new DateTime(2015, 5, 5),
timestampSpecified = true,
actualValueData = new[]
{
new actualValueData {value = 0.1f, name = "Western Region", timestamp = new DateTime(2015, 5, 5)},
new actualValueData {value = 0.1f, name = "some region", timestamp = new DateTime(2015, 5, 5)}
}
});
_sut = new DataController(_eDataProvider);
}
protected override void When()
{
_result = (ViewResult)_sut.Index();
}
[Then]
public void ViewNameShouldBeCorrect()
{
Assert.That(_result.ViewName, Is.EqualTo(""));
}
[Then]
public void ModelShouldBeCorrectType()
{
Assert.That(_result.Model.GetType(), Is.EqualTo(typeof(IndexModel)));
}
[Then]
public void GetAllDayAheadLoadShouldBeCalledOnce()
{
A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).MustHaveHappened(Repeated.Exactly.Once);
}
}
public class WhenViewingWesternRegionLoadLookAheadAndValuesAreUnder50000 : SpecificationBase
{
private DataController _sut;
private ViewResult _result;
private IndexModel _expectedData;
private IProvideeDataFeedData _eDataProvider;
protected override void Given()
{
_expectedData = new IndexModel
{
Message = "Everything is cool",
Region = "Western Region",
Values = new Dictionary<DateTime, float>
{
{new DateTime(2015, 5, 5), 0.1f}
}
};
_eDataProvider = A.Fake<IProvideeDataFeedData>();
A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).Returns(new collectionActualValueData
{
timestamp = new DateTime(2015, 5, 5),
timestampSpecified = true,
actualValueData = new[]
{
new actualValueData {value = 0.1f, name = "Western Region", timestamp = new DateTime(2015, 5, 5)},
new actualValueData {value = 0.1f, name = "some region", timestamp = new DateTime(2015, 5, 5)}
}
});
_sut = new DataController(_eDataProvider);
}
protected override void When()
{
_result = (ViewResult)_sut.Index();
}
[Then]
public void ModelDataShouldBeCorrect()
{
var model = (IndexModel)_result.Model;
Assert.That(model.Message, Is.EqualTo(_expectedData.Message));
Assert.That(model.Region, Is.EqualTo(_expectedData.Region));
Assert.That(model.Values, Is.EquivalentTo(_expectedData.Values));
}
}
public class WhenViewingWesternRegionLoadLookAheadAndValuesAreOver50000 : SpecificationBase
{
private DataController _sut;
private ViewResult _result;
private IndexModel _expectedData;
private IProvideeDataFeedData _eDataProvider;
protected override void Given()
{
_expectedData = new IndexModel
{
Message = "Heavy Load",
Region = "Western Region",
Values = new Dictionary<DateTime, float>
{
{new DateTime(2015, 5, 5), 51000f}
}
};
_eDataProvider = A.Fake<IProvideeDataFeedData>();
A.CallTo(() => _eDataProvider.GetAllDayAheadLoad()).Returns(new collectionActualValueData
{
timestamp = new DateTime(2015, 5, 5),
timestampSpecified = true,
actualValueData = new[]
{
new actualValueData {value = 51000f, name = "Western Region", timestamp = new DateTime(2015, 5, 5)},
new actualValueData {value = 0.1f, name = "some region", timestamp = new DateTime(2015, 5, 5)}
}
});
_sut = new DataController(_eDataProvider);
}
protected override void When()
{
_result = (ViewResult)_sut.Index();
}
[Then]
public void ModelDataShouldBeCorrect()
{
//Assert.That(_result.Model, Is.EqualTo(_expectedData));
var model = (IndexModel) _result.Model;
Assert.That(model.Message, Is.EqualTo(_expectedData.Message));
Assert.That(model.Region, Is.EqualTo(_expectedData.Region));
Assert.That(model.Values, Is.EquivalentTo(_expectedData.Values));
}
}
}
and here is the controller it is testing
public class DataController : Controller
{
private readonly IProvideeDataFeedData _eDataFeedDataProvider;
public DataController(IProvideeDataFeedData eDataFeedDataProvider)
{
_eDataFeedDataProvider = eDataFeedDataProvider;
}
public ActionResult Index()
{
var values = _eDataFeedDataProvider.GetAllDayAheadLoad().actualValueData
.Where(a => a.name == "Western Region")
.ToDictionary(a => a.timestamp, a => a.value);
var model = new IndexModel
{
Region = "Western Region",
Message = values.Any(v => v.Value > 50000) ? "Heavy Load" : "Everything is cool",
Values = values
};
return View(model);
}
}