[英]How to test that a service method was not called
我和我的同事正在討論編寫單元測試的正確方法,以確保當在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,但是我不確定如何對此進行測試。 他建議像這樣使用Moq:
[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();
}
您對此有何想法? 測試未調用服務方法的正確方法是什么? 如何測試用戶表單中的不良數據的正確方法呢?
驗證時:
loginServiceMock.Verify( x => x.Login( It.IsAny<LoginModel>() ), Times.Never() );
您應該在模擬中刪除設置。 為了使代碼在操作中輸入if語句,可以在調用控制器中的操作之前在ModelState中添加模型錯誤。
您的代碼應如下所示:
[TestMethod]
public void Login_Post_Blank_Username_Displays_Error()
{
var controller = GetHomeController();
var loginModel = new LoginModel
{
Username = null
};
controller.ModelState.AddModelError("a key", "a value");
var result = controller.Login( loginModel );
loginServiceMock.Verify( x => x.Login( It.IsAny<LoginModel>() ), Times.Never() );
}
假設已通過屬性注入設置了Mocked LoginService,則可以編寫以下測試。
[TestMethod]
public void LoginPost_WhenUserNameIsNull_VerifyLoginMethodHasNotBeenCalled()
{
//Arrange
var loginServiceMock = new Mock<ILoginService>();
var sut = new HomeController { LoginService = loginServiceMock .Object};
var loginModel = new LoginModel {
Username = null
};
sut.ModelState.AddModelError("fakeKey", "fakeValue");
//Act
sut.Login(loginModel);
//Verify
loginServiceMock.Verify(x => x.Login(loginModel), Times.Never(), "Login method has been called.");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.