当ModelState有效时,单元测试失败

时间:2012-11-20 10:09:38

标签: asp.net-mvc unit-testing nunit

我写了一个单元测试

// 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);

此处单元测试失败,因为模型状态无效。

我的控制器操作是:

[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);
}

我的指数行动:

Public ActionResult Index(int id)
{
    return View();
}

2 个答案:

答案 0 :(得分:1)

是的,它会因为ModelState上的错误而失败,因此您可以比较操作方法的结果类型,检查modelState并检查模型。我建议测试一下这样的代码:

[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);

}

答案 1 :(得分:1)

你真正想要测试的是最终结果。例如,您可能希望确保在模型状态无效时返回正确的ViewName。你只会测试一件事。

如果你以TDD方式这样做......

从失败的测试开始。如果模型状态无效,我只关心预期的结果。在这种情况下,如果模型状态无效,我想要返回特定的视图。

单元测试:

   [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);
    }

受测系统:

    [HttpPost]
    public ActionResult CreateFocus(FocusFormModel focus)
    {
        return new EmptyResult();
    }

现在编写足够的生产代码以使测试通过

    [HttpPost]
    public ActionResult CreateFocus(FocusFormModel focus)
    {
        if (!ModelState.IsValid)
        {
            return View("CreateFocus", focus);
        }

         return new EmptyResult();
    }

测试通过。我们还没有完成。如果模型状态有效,我们还想测试我们得到预期的视图。我们为此编写了一个不同的测试。

从失败的测试开始

   [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"]);
    }

我们重构生产代码以使测试通过。绝对必要的......

    [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 });
    }

现在运行所有测试并确保它们全部通过。重构您的测试以删除任何重复。

请注意,您可能使用NUnit或其他,但我演示了使用MSTest。我会使用手工编写的存根,但是Moq可以直接进行模拟。我还将Model.IsValid切换为!Model.IsValid(仅为方便起见),但你明白了。

希望这有帮助。