2009-06-19 16 views
15

私は単体テストに慣れています。私が書いてきた.NETメンバーシップのいくつかを試そうとしています。Asp.netメンバーシップをテストする方法は?

私はVerifyUserの方法をチェックして、ユーザーの資格情報が有効かどうかをチェックしています。

だから、これはどのように見えるかです:

public bool VerifyUser(string userName, string password) 
    { 
     bool valid = Membership.ValidateUser(userName, password); 
     return valid; 
    } 

そして今、私は私のユニットテストを実行するたびに、それが失敗しました。私は正しい資格と物を渡していることを知っています。それから、私のテストプロジェクト(私の実際のプロジェクトと同じソリューションの下にある)に、接続文字列とファイルを持つweb.configファイルが必要になるかもしれないということが私に浮き彫りになりました。アプリケーションの設定ファイルは、アプリケーションライブラリプロジェクトである可能性があります。

実際のプロジェクトからweb.configファイルをコピーして1日と呼びますか?または、私はそれから部分を取っているだけですか?それとも私はちょうど離れている。

私のデータベースは、.netメンバーシップが自分のデータベースにマージされたカスタムデータベースを使用しています。私の設定ファイルでは、ManagerProviderとroleProviderを指定しなければなりませんでした。

これは私がこれ持って、私は(正確にはログインビュー)私のasp.net MVCのActionResultのいずれかの方法を持っている上で、私のユニットテストは、また後で

[Test] 
    public void TestVerifyUser() 
    { 
     AuthenticateUser authenitcate = new AuthenticateUser(); 
     bool vaild = authenitcate.VerifyUser("chobo3", "1234567"); 


     Assert.That(vaild, Is.True); 
    } 

どのように見えるかです:

をFormsAuthentication.RedirectFromLoginPage(loginValidation.UserName、rememberMe);

これで、ユーザーが行うことのできる単体テストをどのように記述できますか。彼らがホームページから始まってログインページをクリックし、正常にログインしたとします。私は彼らがホームページにリダイレクトされることを望みます。

コードでその表現方法がわかりません。私はかなりRedirectFromLoginPageが働いていると確信しています。私はログインのActionResultメソッドで起こることが3つあるという事実をテストしています。

  1. ユーザーはログインし、どこから来たのかを返信します。
  2. ユーザーはログインに失敗し、LoginViewに返され、エラーメッセージが表示されます。
  3. ユーザーは安全な場所に移動しようとしましたが、ログインページにリダイレクトされました。ログインに成功すると、ReturnUrlを介して安全なページにリダイレクトされます。

だから私は、これらがうまくいくかどうかを調べるためにテストをしたいと思っています。だから私は、ユーザーがホームページのように来て、彼らが後でそれにリダイレクトされるかどうかを確かめる必要があるのです。そして、彼らが安全なページから来た場合、後でリダイレクトされます。

私はまた、NUnit 2.5とVS2008 Proを使用しています。


これは私がテストしようとしているものです。私は、ユーザーが正当なものかどうかを確認しようとしているところです(if文)。私はそれをどのようにテストするかという手がかりはない。

public ActionResult Login(string returnUrl, FormCollection form, bool rememberMe) 
     { 
      LoginValidation loginValidation = new LoginValidation(); 
      try 
      { 
       UpdateModel(loginValidation, form.ToValueProvider()); 

      } 
      catch 
      { 

       return View("Login"); 
      } 

      if (ModelState.IsValid == true) 
      { 

       bool valid = authenticate.VerifyUser(loginValidation.UserName, loginValidation.Password); 

       if (valid == false) 
       { 
        ModelState.AddModelError("frm_Login", "Either the Password or UserName is invalid"); 

       } 
       else if (string.IsNullOrEmpty(returnUrl) == false) 
       { 
        /* if the user has been sent away from a page that requires them to login and they do 
        * login then redirect them back to this area*/ 
        return Redirect(returnUrl); 
       } 
       else 
       { 

        FormsAuthentication.RedirectFromLoginPage(loginValidation.UserName, rememberMe); 
       } 

      } 


      return View("Login"); 
     } 

答えて

7

カスタムメンバーシップコードを2つのレイヤーにリファクタリングすることで、コントローラと多くのカスタムプロバイダをテストできます。データベースとのみ対話するデータアクセスリポジトリと、リポジトリコンポーネントを使用して、メンバーシップAPIサービスレイヤーでは、引数を検証し、EnablePasswordResetなどのパラメータを保持および適用し、データベースの例外またはステータスコードをコントローラの消費に適した形式に変換します。

独自のインターフェイスで各レイヤを指定すると、コンシューマの実装方法に関係なく、コンシューマはそのインターフェイスに書き込むことができます。あなたのアプリが稼働しているときに、あなたのプロバイダはもちろん、これらのインターフェイスを介してデータベースと話していますが、テストのためにリポジトリまたはサービスインターフェイスをモックすることができます。あなたは、データベースやweb.configファイルを混乱させることなく、リポジトリレベルを嘲笑してサービス層をテストすることができます。また、サービス層を模擬してコントローラをテストすることもできます。プロバイダ全体をリファクタリングする必要がない場合でも、サービスインタフェースを作成してコントローラに使用させるだけで、コントローラをテストすることができます。

namespace Domain.Abstract { 
    public interface IRepository { 
     string ConnectionString { get; } 
    } 
} 

namespace Domain.Abstract { 
    public interface IUserRepository : IRepository { 
     MembershipUser CreateUser(Guid userId, string userName, string password, PasswordFormat passwordFormat, string passwordSalt, 
       string email, string passwordQuestion, string passwordAnswer, bool isApproved, 
       DateTime currentTimeUtc, bool uniqueEmail); 
     MembershipUser GetUser(Guid userId, bool updateLastActivity, DateTime currentTimeUtc); 
     PasswordData GetPasswordData(Guid userId, bool updateLastLoginActivity, DateTime currentTimeUtc); 
     void UpdatePasswordStatus(Guid userId, bool isAuthenticated, int maxInvalidPasswordAttempts, int passwordAttemptWindow, 
         DateTime currentTimeUtc, bool updateLastLoginActivity, DateTime lastLoginDate, DateTime lastActivityDate); 
     //.... 
    } 
} 

namespace Domain.Abstract { 
    public interface IUserService { 
    bool EnablePasswordRetrieval { get; } 
    bool EnablePasswordReset { get; } 
    bool RequiresQuestionAndAnswer { get; } 
    bool RequiresUniqueEmail { get; } 
    //.... 

    MembershipUser CreateUser(string applicationName, string userName, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved); 
    MembershipUser GetUser(Guid userId, bool userIsOnline); 
    bool ValidateUser(Guid userId, string password); 
    //... 
    } 
} 

namespace Domain.Concrete { 
    public class UserService : IUserService { 
    private IUserRepository _userRepository; 


    public UserService(IUserRepository userRepository) { 
     _userRepository = userRepository; 
    } 
    //... 
    public bool ValidateUser(Guid userId, string password) { 
     // validate applicationName and password here 
     bool ret = false; 
     try { 
      PasswordData passwordData; 
      ret = CheckPassword(userId, true, true, DateTime.UtcNow, out passwordData); 
     } 
     catch (ObjectLockedException e) { 
      throw new RulesException("userName", Resource.User_AccountLockOut); 
     } 
     return ret; 
    } 

    private bool CheckPassword(Guid userId, string password, bool updateLastLoginActivityDate, bool failIfNotApproved, 
           DateTime currentTimeUtc, out PasswordData passwordData) { 
     passwordData = _userRepository.GetPasswordData(userId, updateLastLoginActivityDate, currentTimeUtc); 

     if (!passwordData.IsApproved && failIfNotApproved) 
      return false; 

     string encodedPassword = EncodePassword(password, passwordData.PasswordFormat, passwordData.PasswordSalt); 
     bool isAuthenticated = passwordData.Password.Equals(encodedPassword); 

     if (isAuthenticated && passwordData.FailedPasswordAttemptCount == 0 && passwordData.FailedPasswordAnswerAttemptCount == 0) 
      return true; 
     _userRepository.UpdatePasswordStatus(userId, isAuthenticated, _maxInvalidPasswordAttempts, _passwordAttemptWindow, 
              currentTimeUtc, updateLastLoginActivityDate, 
              isAuthenticated ? currentTimeUtc : passwordData.LastLoginDate, 
              isAuthenticated ? currentTimeUtc : passwordData.LastActivityDate); 

     return isAuthenticated; 
    } 
} 
1

残念ながら、あなたのweb.configまたはapp.configをコピーしてそのまま動作させることはできません。その理由は、アセンブリがNUnitプロセスの内部で実行されており、アプリケーションの下で実行されていないためです。

あなたの状況を改善するには、呼び出しているメンバーシップメンバーを偽装したり、スタブしたり、web.configに保存した設定に対するConvention over Configurationアプローチを実行する必要があります。

そこに多くのモックフレームワークがありますが、ここではカップルです:あなたは

static ConfigurationSettings 
{ 
    static String SomeSetting 
    { 
     get 
     { 
      var result = "HARDCODEDVALUE"; 
      if (ConfigurationManager.AppSettings["SOMEKEY"] != null) 
       result = ConfigurationManager.AppSettings["SOMEKEY"]; 
      return result; 
    } 
} 

:コンフィギュレーション・アプローチの上に条約に従うことを、Rhino MocksMoq

また、あなたはこのような何かを行うことができます

//this is how the old code might look 
var mySetting = ConfigurationManager.AppSettings["SOMEKEY"]; 
//use the setting 

//this is how the new code would look 
var mySetting = ConfigurationSettings.SomeSetting; 
//use the setting 

このようにして、あなたのアプリケーションの下で実行すると次のようになります。あなたが保存した設定を使用します。

+0

申し訳ありませんが、私は私はモック読ん 「コンフィギュレーション・アプローチを超える大会」を理解していない。同様に少し冗長、リポジトリおよびサービスのインタフェースが何かを見て可能性がある場合

。具体的には、私は持っている本。そのようなものを使って何かをするのか? このリンクが見つかりましたが、Nunitを使用していてMbUnitを使用しているので動作しません。 http://aspalliance.com/1590 – chobo2

+0

@ chobo2私はそれをどのように使用するかについて何かを書きます。模擬フレームワークは間違いなくインターフェイスを使用することに正当な理由があります。インタフェースを使用すると、良好なデカップリングが得られます。ただし、すべてのモッキングフレームワークでインターフェイスを使用する必要はありません。また、NUnitとMbUnitは多くの点で似ています。そのため、MbUnitで行われる処理は、NUnitとの関連が考えられます。いくつかの調査を行う価値があります。 – Joseph

+0

ありがとうございました。私はまだ実際にインターフェイスを理解していないし、単体テストになると本当にそれらと一緒に考えていない。だからうまくいけば、これらのフレームワークの1つが少し楽になります。 どちらをお勧めしますか?私は "Moq"がlinq sytanxを使用しているので、もし私がlinqについてよく知らないので、それが私には良いとすれば、そのバットの権利があるかどうかはわかりません。 また、これらのフレームワークはnunitとどのように機能しますか?私のテストや何を実行するために、まだnunitを使用していますか? – chobo2

3

Asp.Netメンバーシップシステムは、Asp.Net要求のコンテキストで動作するように設計されています。したがって、ここには3つのオプションがあります。

  1. このような依存関係に直面したほとんどの人は、その周りにシンラッパーを作成します。ラッパーは何もしません、すべての呼び出しを根本的な依存関係にリダイレクトします。だから、彼らはただそれをテストしない。 AuthenticateUserはそのようなラッパーです。おそらく、すべてのメソッドを仮想化したり、インターフェイスを抽出してモック可能にする必要がありますが、それは別の話です。
  2. TypeMockアイソレータと模擬メンバーシップを使用してください。
  3. Ivonna frameworkを使用し、Asp.Netコンテキストでテストを実行します(これは統合テストになります)。
関連する問題