あなたが持っている現在の例でのユニットテストについてはあまり詳しく説明できません。あなたが得たのは、で結ばれShowDetails
たものを返す単一のメソッドがあるからです。返品するのは返品タイプのみですので、に変更することができます。次に、テストできるのは、と関連付けられたモデルがタイプであるかどうかだけです。View
UsersIdentificationViewModel
View
ViewResult
View
UsersIdentificationViewModel
簡単な例をとれば、MVCでの単体テストをもう少し詳しく説明できます。を選択して新しいMVCアプリケーションを作成すると、がデフォルトとして定義され、ログイン、登録、パスワードの変更などのアクションが含まれているinternet template
ことがわかります。AccountController
LogOn
でアクションを実行しましょうAccountController
。
AccountController.cs
public class AccountController : Controller
{
private readonly IAuthProvider _authProvider;
public AccountController(IAuthProvider authProvider)
{
_authProvider = authProvider;
}
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (_authProvider.ValidateUser(model.UserName, model.Password))
{
_authProvider.SetCookie(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
return View(model);
}
...
}
FormsAuthentication
封印されたクラスとの依存関係を回避するためにAccountController
、インターフェイスを使用しIAuthProvider
て単体テストを簡素化しました。
IAuthProvider.cs
public interface IAuthProvider
{
bool ValidateUser(string username, string password);
void SetCookie(string username, bool rememberMe);
bool CreateUser(string username, string password, string email, out string error);
bool ChangePassword(string username, string oldPassword, string newPassword);
void SignOut();
}
LogOnModel.cs
public class LogOnModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
アクション内の多くのif..else条件に気付くことができLogOn
、それらは単体テストの良い候補です。
アクションの単体テストを少なくとも4つ作成します。
- 有効なクレデンシャルを入力したら、アクションが渡されたURLにリダイレクトする必要があることを確認します。
- ユーザーをアクションにリダイレクトする必要がなく
returnUrl
、有効なクレデンシャルを渡すことを確認します。AccountController
Home
- 無効なクレデンシャルを渡すと、アカウントコントローラーがエラーのあるビューを返す必要があることを確認します。
- 検証エラーが発生したときに、コントローラーがエラーのあるビューを返す必要があることを確認します。
これが私がとを使って書いた単体テストMSTest
ですRhinoMocks
。
AccountControllerTests.cs
[TestClass]
public class AccountControllerTests
{
private AccountController _accountController;
private IAuthProvider _mockAuthProvider;
[TestInitialize]
public void SetUp()
{
//** Arrange
_mockAuthProvider = MockRepository.GenerateStub<IAuthProvider>();
_accountController = new AccountController(_mockAuthProvider);
}
[TestCleanup]
public void CleanUp()
{
}
/// <summary>
/// This test is to verify on entering valid credentials the action should redirect to the passed url.
/// </summary>
[TestMethod]
public void LogOn_Action_Valid_Credentials_With_ReturnUrl_Test()
{
//** Arrange
var logonModel = new LogOnModel
{
UserName = "trigent",
Password = "password",
RememberMe = true
};
// stub the ValidateUser to return "true" to pretend the user is valid.
_mockAuthProvider.Stub(x => x.ValidateUser(logonModel.UserName, logonModel.Password)).Return(true);
//** Act
var actual = _accountController.LogOn(logonModel, "/");
//** Assert
// verify RedirectResult is returned from action
Assert.IsInstanceOfType(actual, typeof(RedirectResult));
// verify the redirect url is same as the passed one.
Assert.AreEqual(((RedirectResult)actual).Url, "/");
}
/// <summary>
/// This test is to verify on passing valid credentials without returnUrl the account controller
/// should redirect the user to the "Home" action.
/// </summary>
[TestMethod]
public void LogOn_Action_Valid_Credentials_Without_ReturnUrl_Test()
{
//** Arrange
var logonModel = new LogOnModel
{
UserName = "trigent",
Password = "password",
RememberMe = true
};
// stub the ValidateUser to return "true" to pretend the user is valid.
_mockAuthProvider.Stub(x => x.ValidateUser(logonModel.UserName, logonModel.Password)).Return(true);
//** Act
var actual = _accountController.LogOn(logonModel, string.Empty);
//** Assert
// verify RedirectToRouteResult is returned from action
Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
// verify the controller redirecting to "Home" action.
var routeValues = ((RedirectToRouteResult)actual).RouteValues;
Assert.AreEqual("Home", routeValues["controller"].ToString());
Assert.AreEqual("Index", routeValues["action"].ToString());
}
/// <summary>
/// This test is to verify on passing invalid credentials the account controller should return the login view
/// with error messages.
/// </summary>
[TestMethod]
public void LogOn_Action_Invalid_Credentials_Test()
{
//** Arrange
var logonModel = new LogOnModel
{
UserName = "trigent",
Password = "password",
RememberMe = true
};
// stub the ValidateUser to return "false" to pretend the user is invalid.
_mockAuthProvider.Stub(x => x.ValidateUser(logonModel.UserName, logonModel.Password)).Return(false);
//** Act
var actual = _accountController.LogOn(logonModel, string.Empty);
//** Assert
// verify ViewResult is returned from action
Assert.IsInstanceOfType(actual, typeof(ViewResult));
// verify the controller throws error.
var modelStateErrors = _accountController.ModelState[""].Errors;
Assert.IsTrue(modelStateErrors.Count > 0);
Assert.AreEqual("The user name or password provided is incorrect.", modelStateErrors[0].ErrorMessage);
}
/// <summary>
/// This test is to verify when there is a validation error the controller should return the same login view.
/// </summary>
[TestMethod]
public void LogOn_Action_Invalid_Input_Test()
{
//** Arrange
_accountController.ModelState.AddModelError("UserName", "UserName is Required.");
//** Act
var actual = _accountController.LogOn(new LogOnModel(), string.Empty);
//** Assert
// verify ViewResult is returned from action
Assert.IsInstanceOfType(actual, typeof(ViewResult));
}
}