3

MVC 4 アプリケーションでの TDD の概念を理解しようとしています。私がネット上で見つけたすべての例は、MVC 4 アプリケーションの場合の単体テストでテストする必要がある概念を説明していません。

では、単体テストを作成するとき、コントローラーでテストしようとしている主なポイントは何ですか?

可能であれば、この例で説明してください。

public class UsersIDentController : AuthorizedController
{    
    private readonly IUserDetailsService userDetailsService;

    public UsersIDentController(IUserDetailsService userDetailsService,
            IServiceLocator serviceLocator): base(serviceLocator)
    {
    }    

    //
    // GET: /UsersIdentification/
    [AllowAnonymous]
    public ActionResult ShowDetails()
    {
        UsersIdentificationViewModel model = new UsersIdentificationViewModel();
        return View(model);
    }
}

このコントローラーの単体テストを作成する (ユーザー データを取得する) 場合、単体テストで何をテストしますか。

ありがとう。

4

2 に答える 2

7

あなたが持っている現在の例でのユニットテストについてはあまり詳しく説明できません。あなたが得たのは、で結ばれShowDetailsたものを返す単一のメソッドがあるからです。返品するのは返品タイプのみですので、に変更することができます。次に、テストできるのは、と関連付けられたモデルがタイプであるかどうかだけです。ViewUsersIdentificationViewModelViewViewResultViewUsersIdentificationViewModel

簡単な例をとれば、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つ作成します。

  1. 有効なクレデンシャルを入力したら、アクションが渡されたURLにリダイレクトする必要があることを確認します。
  2. ユーザーをアクションにリダイレクトする必要がなくreturnUrl、有効なクレデンシャルを渡すことを確認します。AccountControllerHome
  3. 無効なクレデンシャルを渡すと、アカウントコントローラーがエラーのあるビューを返す必要があることを確認します。
  4. 検証エラーが発生したときに、コントローラーがエラーのあるビューを返す必要があることを確認します。

これが私がとを使って書いた単体テスト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));
   }
}
于 2012-11-13T10:30:26.753 に答える
1

ShowDetails メソッドをテストすると、正しいタイプのモデルを含むビューが返されるかどうかを確認できます。

これを行うには、MVC Contribを使用できます。これには、使用できる単体テスト アサーションがあります。すべての単体テスト ドキュメントは、http: //mvccontrib.codeplex.com/wikipage?title=TestHelper&referringTitle= Documentation にあります。

于 2012-11-13T09:33:21.413 に答える