Reputation: 59
I wrote a unit test
// Arrange
FocusController controller = new FocusController();
controller.ModelState.AddModelError("", "mock error message");
// Act
FocusFormModel focus = new FocusFormModel();
focus.FocusName = "Mock Focus";
focus.Description = "Mock Description";
focus.GroupId = 1;
var result = controller.CreateFocus(focus) as RedirectToRouteResult;
//// Assert
Assert.That(result, Is.Not.Null);
here the unit test fails as model state is not valid.
My controller action is:
[HttpPost]
public ActionResult CreateFocus(FocusFormModel focus)
{
if (ModelState.IsValid)
{
var createdfocus = focusService.GetFocus(focus.FocusName);
return RedirectToAction("Focus", new { id = createdfocus.FocusId });
}
return View("CreateFocus",focus);
}
My Index action:
Public ActionResult Index(int id)
{
return View();
}
Upvotes: 1
Views: 1725
Reputation: 38608
Yes, it will fail because you have an error on the ModelState, so you could compare the result type of your action method, check the modelState and check the model as well. I recommend test doing a code like this:
[TestMethod]
public void Should_have_return_an_error()
{
FocusController controller = new FocusController();
// you add this value on ModelState to force the error
controller.ModelState.AddModelError("", "mock error message");
// Act
FocusFormModel focus = new FocusFormModel();
focus.FocusName = "Mock Focus";
focus.Description = "Mock Description";
focus.GroupId = 1;
const string viewNameResult = "Index"; //or whatever your action tested should return
// it will return the error
var result = controller.CreateFocus(focus) as ViewResult;
//// Assert the Action type result...
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
//// Assert the model..
Assert.AreEqual(focus, result.Model);
//// Aseert the ModelState
Assert.IsFalse(result.ModelState.IsValid);
Assert.AreEquals(result.ViewName, viewNameResult);
}
Upvotes: 1
Reputation: 6992
What you really want to test is the end result. For example you might want to make sure the correct ViewName returned when the model state is invalid. You would only test one thing.
If you do this in a TDD way ...
Start with a failing test. I only care about the expected outcome if the model state is not valid. In the case I want a specific view to be returned if the model state is not valid.
Unit Test:
[TestMethod]
public void CreateFocus_WhenModelStateIsNotValid_ReturnsViewNameCreateFocus()
{
// Arrange
var stubFocusService = new Mock<IFocusService>();
var controller = new FocusController(stubFocusService.Object);
controller.ModelState.AddModelError("", "fake error message");
const string expectedViewNameWhenModelError = "CreateFocus";
// Act
var result = controller.CreateFocus(It.IsAny<FocusFormModel>()) as ViewResult;
// Assert
Assert.AreEqual(expectedViewNameWhenModelError, result.ViewName);
}
System Under Test:
[HttpPost]
public ActionResult CreateFocus(FocusFormModel focus)
{
return new EmptyResult();
}
Now write just enough production code to make the test pass
[HttpPost]
public ActionResult CreateFocus(FocusFormModel focus)
{
if (!ModelState.IsValid)
{
return View("CreateFocus", focus);
}
return new EmptyResult();
}
The test passes. We are not done yet. We also want to test we get the expected view if the model state is valid. We write a different test for that.
Start with a failing test
[TestMethod]
public void CreateFocus_WhenModelStateIsValid_EnsureRouteNameFocus()
{
// Arrange
var stubFocusService = new Mock<IFocusService>();
stubFocusService.Setup(x => x.GetFocus(It.IsAny<string>())).Returns(new Focus());
var controller = new FocusController(stubFocusService.Object);
const string expectedRouteNameWhenNoModelError = "Focus";
// Act
var result = controller.CreateFocus(new FocusFormModel()) as RedirectToRouteResult;
// Assert
Assert.AreEqual(expectedRouteNameWhenNoModelError, result.RouteValues["action"]);
}
We refactor the production code to make the test pass. Again what absolutely necessary..
[HttpPost]
public ActionResult CreateFocus(FocusFormModel focus)
{
if (!ModelState.IsValid)
{
return View("CreateFocus", focus);
}
var createdfocus = _focusService.GetFocus(focus.FocusName);
return RedirectToAction("Focus", new { id = createdfocus.FocusId });
}
Now run all tests and ensure they all pass. Refactor your tests to remove any duplication.
Note that you probably use NUnit or other, but I demonstrated using MSTest. I would have used hand written stubs, but mocking is straightforward here with Moq. I also switched the Model.IsValid to !Model.IsValid (just for my convenience), but you get the idea.
Hope this helps.
Upvotes: 1