【发布时间】:2012-06-20 23:42:19
【问题描述】:
我和我的同事正在讨论编写单元测试的正确方法,以确保用户在我们的 ASP.NET MVC 2 应用程序的表单中输入错误数据时收到错误。以下是我们过去所做的,从模型开始:
public class LoginModel
{
public string Username { get; set; }
}
这是控制器动作:
[HttpPost]
public ActionResult Login( LoginModel loginModel )
{
if ( loginModel.Username == null )
{
ModelState.AddModelError( "Username", "Username is required!" );
return View( loginModel );
}
LoginService.Login( loginModel );
}
最后,测试方法如下:
[TestMethod]
public void Login_Post_Blank_Username_Displays_Error()
{
var controller = GetHomeController();
var loginModel = new LoginModel
{
Username = null
};
var result = controller.Login( loginModel );
Assert.IsInstanceOfType( result, typeof( ViewResult ) );
var view = (ViewResult)result;
Assert.IsNotNull( view.ViewData.ModelState["Username"].Errors.First().ErrorMessage );
}
他向我指出,这确实不是针对这种情况编写测试的正确方法。出于一个原因,它非常脆弱 - 将 Username 属性更改为其他任何东西都会破坏测试。其次,最好依靠 DataAnnotations 并针对控制器正在做的事情进行测试。因此,我们的新模型如下所示:
public class LoginModel
{
[Required( ErrorMessage = "Username is required!" )]
public string Username { get; set; }
}
我们的控制器动作会变成这样:
[HttpPost]
public ActionResult Login( LoginModel loginModel )
{
if ( !Model.IsValid() )
{
return View( loginModel );
}
LoginService.Login( loginModel );
}
问题出在单元测试上,它完全没有注意到 DataAnnotations,所以测试失败了。我的同事说我们真正应该测试的是没有调用 LoginService,但我不确定如何测试。他建议像这样使用起订量:
[TestMethod]
public void Login_Post_Blank_Username_Displays_Error()
{
var controller = GetHomeController();
var loginModel = new LoginModel
{
Username = null
};
loginServiceMock.Setup( x => x.Login( It.IsAny<LoginModel>() ) )
.Callback( () => Assert.Fail( "Should not call LoginService if Username is blank!" ) );
var result = controller.Login( loginModel );
loginServiceMock.Verify();
}
您对此有何看法?测试未调用服务方法的正确方法是什么?在用户表单中测试不良数据的正确方法是什么?
【问题讨论】:
标签: asp.net-mvc unit-testing moq mstest data-annotations