このコードを理解する助けが必要
-
06-07-2019 - |
質問
ユニットテストを学習しようとしています。私は、asp.net mvc 1.0で作成しているMemembershipの一部を単体テストしようとしています。私はMVCに関する本をフォローしていますが、誰かが私のために片付けてくれることを願っています。
フレームワークにNunitとMoqを使用しています。
質問1:
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
{
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Provider = provider ?? Membership.Provider;
}
" ??"が混乱しています私は前にそれを見たことがありませんか。ここで本当に何が起こっているのかさえ知らないように。彼らがインターフェースを渡して「???」マークが発生し、新しいFormsAuthenticationWraperが作成されますか?
質問2。
public AuthenticationController(): this(null, null)
{
}
これがデフォルトのコンストラクタであることは知っていますが、なぜ&quot ;: this(null、null)"しています。
実装と同様に?そしてこれも何を指しているのか。それに加えて、なぜそれを除外できないのですか?そして、デフォルトのコンストラクタをそのまま使用します。
質問3。
本(asp.net mvc 1.0)では、Memembershipプロバイダーを実装するのがかなりの作業になることについて、かなりの作業になることについて説明しています。したがって、彼らはmoqモックアップフレームワークを使用して、生活を楽にします。
今、私の質問は、「FormsAuthentication」でmoqを使用しないことです。代わりに、インターフェースを作成します
public interface IFormsAuthentication
{
void SetAuthCookie(string userName, bool createPersistentCookie);
void SignOut();
}
次にラッパーを作成します
パブリッククラスFormsAuthenticationWrapper:IFormsAuthentication { public void SetAuthCookie(string userName、bool createPersistentCookie) { FormsAuthentication.SetAuthCookie(userName、createPersistentCookie); } public void SignOut() { FormsAuthentication.SignOut(); }
}
そして最後にプロパティ
public IFormsAuthentication FormsAuth
{
get;
private set;
}
メンバーシップの場合と同じように、
public static MembershipProviderプロバイダー { 取得する; プライベートセット; }
何を変更すればよいのかわかりません。この行も何を変更しますか?
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
また、FormsAuthentication InterfaceとWrapperに別のメソッドを追加しようとしました。
public void RedirectFromLoginPage(string userName、bool createPersistentCookie) { FormsAuthentication.RedirectFromLoginPage(userName、createPersistentCookie); }
まだ何が起こっているのかわかりませんが、ユニットテストは常に失敗します。それを修正するために何をしようとしても関係ありません。
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
{
FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);
}
}
return View("Login");
Here is my test
[テスト] public void Test_If_User_Is_Redirected_Back_To_Page_They_Came_From_After_Login() { System.Diagnostics.Debugger.Break();
var formsAuthenticationMock = new Mock<AuthenticationController.IFormsAuthentication>();
var membershipMock = new Mock<MembershipProvider>();
membershipMock.Setup(m => m.ValidateUser("chobo2", "1234567")).Returns(true);
// Setup controller
AuthenticationController target = new AuthenticationController(formsAuthenticationMock.Object, membershipMock.Object);
// Execute
FormCollection form = new FormCollection();
form.Add("Username", "chobo2");
form.Add("password", "1234567");
ViewResult actual = target.Login(null, form, false) as ViewResult;
Assert.That(actual.View, Is.EqualTo("home"));
formsAuthenticationMock.Verify();
}
Actualは常にnullに戻ります。 ViewResult、RedirectResult、RedirectToRouteResultを試しましたが、誰もがnullで戻ってきます。最初に奇妙なことに気付いたので、なぜこれが起こっているのかわかりません
FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);
ビューを停止せず、リダイレクトを開始します。私は最初にこの行にヒットすると、returnステートメントのようであり、他のコードは実行されないが、htisはそうではないようだと思ったので、これが問題になるかどうかわかりません。
ありがとう
解決
質問1
??
は、 null合体演算子 。C#2.0以降の非常に便利な機能です。
あなたの場合、
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
は、単に formsAuth
を FormsAuth
にnullで割り当てないことを意味します。その場合、 new FormsAuthenticationWrapper()
&quot;を割り当てます。これは基本的に、コード内のnull参照を防ぐ方法です。また、次の条件式のショートカットと考えることもできます。
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
質問2
this(null、null)
の使用は、 コンストラクターチェーン 。つまり、2つのパラメーターを受け取る同じクラス(親クラスの base
ではなく this
)のコンストラクターは、本体の前に呼び出す必要があるということです。コンストラクタの実行されます。
コンストラクタのオーバーロードは、開発者がデフォルトのプロパティ/設定を使用したいだけのときに新しいオブジェクトを簡単に作成できるようにする一般的な方法です。
質問3
他の人が述べたように、これは本当に別の質問として属します。前の2つとは異なり、C#の言語機能ではなく、コンテキスト/コードにはるかに固有です。
更新
さて、私が今やったことは、実際には2つのコンストラクターを書き直したものです。別の(実質的に同等の)フォームに配置する方が少し明確で、おそらくより良い設計プラクティスだと思うからです。ここでは、null合体演算子は必要ありません。
public AuthenticationController()
: this(new FormsAuthenticationWrapper(), Membership.Provider)
{
}
public AuthenticationController(IFormsAuthentication formsAuth,
MembershipProvider provider)
{
this.FormsAuth = formsAuth;
this.Provider = provider;
}
この形式では、2つのパラメーターをとるコンストラクターが単にクラス変数を引数の値に割り当てることは明らかです。パラメーターなしのコンストラクター(多くの場合、 default コンストラクターと呼ばれます)は、単に default FormsAuth
および Provider
オブジェクトを使用して新しいオブジェクトを作成します、コンストラクタチェーンで指定されます。
他のヒント
質問1:?? null合体演算子。 ??演算子は、式の左側に指定された値がnullかどうかをチェックし、nullの場合、式の右側に示される代替値を返します。
あなたの状況では、 formsAuth
がnullかどうかをチェックし、nullの場合は新しいFormsAuthenticationWrapper()を返します。
??演算子は、「これを使用する、nullでない限り、この場合はこの他のものを使用する」と言っています。
したがって、次のコード行:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
と同じ:
if ( formsAuth != null ) FormsAuth = formsAuth
else FormsAuth = new FormsAuthenticationWrapper();
第2四半期への回答
コンストラクタをオーバーロードしています。
呼び出しを意味する場合
Foo()
は呼び出しと同じです
Foo(null, null)
質問1:
??
演算子は、「nullでない場合は左側にあるものをすべて取得します。nullでない場合は、右側にあるものをすべて取得します」と言います。あなたのコード:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
は同等です
if (formsAuth != null) {
FormsAuth = formsAuth;
} else {
FormsAuth 0 new FormsAuthenticationWrapper();
}
質問2: :this(null、null)
構文は&quot; constructor inheritance&quot;の省略形です。 (私の命名...)。あなたのコード
public AuthenticationController(): this(null, null)
{
}
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
{
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Provider = provider ?? Membership.Provider;
}
は同等です
public AuthenticationController()
{
FormsAuth = new FormsAuthenticationWrapper();
Provider = Membership.Provider;
}
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
{
FormsAuth = formsAuth;
Provider = provider;
}
質問2
public AuthenticationController(): this(null, null)
{
}
AuthenticationControllerのパラメーターなしコンストラクターは、IFormsAuthenticationとMembershipProviderを受け取るコンストラクターを呼び出し、2つのnull値を渡します(これは、no-paramコンストラクターコードブロック内のコードが実行される前に行われます)。 2つの引数コンストラクターはnull結合(??)演算子を使用して変数を割り当て、渡された引数はnullであるため、Membership.Providerオブジェクトと共に新しいMembershipProviderが使用されます。
このコンストラクタが明示的に定義されていなかった場合、デフォルトのno-paramコンストラクタが使用されていました。メンバー変数が初期化されていないため、新しいAuthenticationControllerが(コンストラクターに引数を渡さずに)作成された場合、これは予期しない動作につながる可能性があります。
質問1:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Provider = provider ?? Membership.Provider;
は次と等しい:
FormsAuth = (formsAuth == null ? new FormsAuthenticationWrapper() : formsAuth);
Provider = (provider == null ? Membership.Provider : provider);
質問2:
formsAuth引数とプロバイダーコンストラクター引数の両方にnullを渡すだけです。私見では良い習慣ではありません。引数のない別のコンストラクターの方が適しています。
編集:これは意味がありません。申し訳ありませんが、私は急いでいて、それが別のコンストラクタを呼び出すコンストラクタであることを本当に知りませんでした。
今は質問3に答える時間がないので、後でそれに行きます...