I have 2 concerns about my unit test method:
- Do I test too much in one test method?
- How can my test method name reflect all test expectations?
I asked myself when my method name says: ReturnInvalidModelState, then my 2 other Asserts are not correct. At least concerning the method name…
[Test]
public void Create_TemplateAlreadyExists_ReturnInvalidModelState()
{
// ARRANGE
TemplateViewModel templateViewModel = new TemplateViewModel {
Name = "MyTest"
};
Mock<ITemplateDataProvider> mock1 = new Mock<ITemplateDataProvider>();
Mock<IMappingEngine> mock2 = new Mock<IMappingEngine>();
TemplateController controller =
new TemplateController(mock1.Object, mock2.Object);
mock1.Setup(m => m.TemplateExists("MyTest")).Returns(true);
// Set ModelState.IsValid to false
controller.ModelState.AddModelError("Name",
"This name already exists.");
// ACT
ActionResult result = controller.Create(templateViewModel);
// ASSERT
Assert.IsFalse(controller.ModelState.IsValid);
Assert.IsInstanceOfType(typeof(PartialViewResult), result);
Assert.AreEqual(templateViewModel, ((PartialViewResult)result).Model);
}
[HttpPost]
public ActionResult Create(TemplateViewModel templateViewModel)
{
if (ModelState.IsValid
&& !_templateDataProvider.TemplateExists(templateViewModel.Name))
{
Template template =
Mapper.Map<TemplateViewModel, Template>(templateViewModel);
_templateDataProvider.AddTemplate(template);
return new JsonNetResult(new { success = true });
}
ModelState.AddModelError("Name", "This name already exists.");
return PartialView(templateViewModel);
}
Yes, I think that you are testing for too many things.
Start with renaming your test method. Your method signature should describe action, scenario and expected outcome.
If I were to rename your method, than I would end up with the following:
Your test is concerned with three things, rather than one. When it fails, you won’t know straight away why it has failed.
Consider re-factoring this into smaller tests and encapsulating some of the arrangement logic so that it can be re-used.
Edit:
You made a good point in your comment regarding single test method having a single assertion. I agree with you on that one, as good as it sounds, often it’s not sufficient.
Say I have the following action method:
I have the following unit test for this method:
As you can see, I set up multiple expectations on my mock:
At the end of the test I have a single assertion that checks whether user was re-directed to the correct route.
So where do I check my assertions? I create another method that makes sure that my expectations have been met:
So you are right, I have three assertions instead of one, but I structure my code in such a way so it appears that I have only one assertion.