【问题标题】:unit testing controller单元测试控制器
【发布时间】:2011-06-22 10:42:06
【问题描述】:

我有一个非常简单的场景:

[HttpGet]
public ActionResult CreateUser()
{
    return View();
}

[HttpGet]
public ActionResult Thanks()
{
    return View();
}

[HttpPost]
public ActionResult CreateUser(CreateUserViewModel CreateUserViewModel)
{
    if (ModelState.IsValid)
    {
    return View("Thanks");
    }

    return View(CreateUserViewModel);
}

我的单元测试使用来自 mvc contrib 的 testhelper:

[Test]
public void UserController_CannotCreateUserWithNoLastName()
{
    // arrange
    UsersController UsersController = new UsersController();
    CreateUserViewModel CreateUserViewModel = new CreateUserViewModel();
    CreateUserViewModel.LastName = "";

    // act
    ActionResult result = UsersController.CreateUser(CreateUserViewModel);

    // assert
    result.AssertViewRendered().ForView("CreateUser");
}

当我打开浏览器并尝试提交无效用户(无姓氏)时,它会重定向到 createuser 表单,但单元测试失败(它说它重定向到感谢)。为什么是这样?有人能看出有什么不对吗?谢谢!

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3


    【解决方案1】:

    在您的单元测试中,您应该模拟您的模型有错误,因为这是您要测试的内容(错误路径)。在您的测试中,模型是有效的,这就是为什么它会将您重定向到“谢谢”视图。要模拟错误,您可以在“act”部分之前的单元测试中执行此操作:

    UsersController.ModelState.AddModelError("username", "Bad username"); 
    

    看看那个例子:http://www.thepursuitofquality.com/post/53/how-to-test-modelstateisvalid-in-aspnet-mvc.html

    更多关于 AddModelError 方法在这里:http://msdn.microsoft.com/en-us/library/system.web.mvc.modelstatedictionary.addmodelerror.aspx

    【讨论】:

    • 我刚刚在这里读到这样的内容:thepursuitofquality.com/post/53/… 我不得不承认我并不完全理解。基本上我不需要创建一个无效的视图模型,只需添加这个错误来测试控制器是否做出适当的反应。这是正确的吗?但是我如何测试控制器是否能正确处理无效的视图模型呢?谢谢。
    • 您要测试的是您的操作中的逻辑。 ModelState.IsValid == true 的一个单元测试和 ModelState.IsValid == false 的另一个单元测试。对于第二个测试,您应该模拟模型中存在错误。当应用程序运行时,模型的验证发生在您的操作执行之前。你没有在单元测试中进行验证,因为你没有运行所有的 ASP.NET MVC 框架。这就是为什么你应该在你的模型中模拟一个错误来只测试你的逻辑。 ASP.NET MVC 团队已经测试了验证管道。
    【解决方案2】:

    我相信您正在为 LastName 使用 DataAnnotations,因此验证将由 ModelBinder 执行。 单元测试将跳过 ModelBinder 和验证。

    查看SO question 了解更多详情 - 手动调用 Controller 上的 UpdateModel

    【讨论】:

    • 是的,我正在使用 DataAnnotations。我看不到如何在测试中调用 UpdateModel。是这个意思吗?
    • 验证将由 ModelBinder 执行,因此如果您调用 updatemodel - 验证将在您的视图模型上执行,并且相应的错误将添加到模型中。