2009-06-22 174 views
2

我正在嘗試學習單元測試。我正在嘗試單元測試我在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) 
     { 
     } 

我知道這是默認的構造函數,但我不知道爲什麼 「:這個(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 { 公共無效SetAuthCookie(用戶名字符串,布爾createPersistentCookie) { FormsAuthentication.SetAuthCookie(用戶名,createPersistentCookie); } public void SignOut() { FormsAuthentication.SignOut(); }

} 

然後最後一個屬性

public IFormsAuthentication FormsAuth 
     { 
      get; 
      private set; 
     } 

凡與會員他們只有

公共靜態的MembershipProvider提供商 { 搞定; 私人設置; }

我不知道該怎麼改變東西。就像我會改變這條線一樣?

FormsAuth = formsAuth ?? ??新的FormsAuthenticationWrapper();

我也嘗試添加另一種方法到FormsAuthentication接口和包裝。

公共無效RedirectFromLoginPage(用戶名字符串,布爾createPersistentCookie) { FormsAuthentication.RedirectFromLoginPage(用戶名,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 

[測試] 公共無效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(); 

    } 

實際總是回到零。我嘗試了ViewResult,RedirectResult和RedirectToRouteResult,但每個人都回來了空。所以,我不知道爲什麼發生這種情況,因爲我覺得很奇怪:第一,

     FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe); 

不停止的觀點,並開始重定向。我一開始認爲一旦它碰到這一行就像是一個return語句,它不會執行其他代碼,但htis似乎不是這種情況,所以我不確定這是否會成爲問題。

謝謝

+1

你應該把你的問題分成不同的帖子。問題1和問題2是相關的,可能是一個職位,但問題3應該是最有可能的。 – 2009-06-22 12:57:25

+0

問題3比一個更多的問題真的 – 2009-06-22 12:59:52

回答

11

問題1

??被稱爲null-coalescing operator,並且是一個非常有用的功能C#2.0以上。

在你的情況,

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

僅僅意味着 「分配給formsAuth除非FormsAuth爲null,在這種情況下分配new FormsAuthenticationWrapper()」。這基本上是防止代碼中的空引用的一種方法。你也可以把它作爲下列條件表達式的快捷方式:

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper(); 

問題2

採用this(null, null)被稱爲constructor chaining。所有這一切都意味着,在構造函數的主體執行之前,應該調用同一類中的構造函數(因此this,而不是父類的base),它需要兩個參數。

重載構造函數是一種常見的做法,使開發人員只需要使用默認屬性/設置時便可創建新對象。

問題3

正如其他人所說,這確實屬於一個單獨的問題。與前兩個不同的是,它對上下文/代碼更具體,而不是C#的語言特性。

更新

好吧,我現在所做的就是這裏實際上改寫了兩個構造函數,因爲我認爲他們將在另一個(實際上等於)的形式可能會有點更清晰,可能是更好的設計實踐過。這裏不需要空合併運算符。

public AuthenticationController() 
    : this(new FormsAuthenticationWrapper(), Membership.Provider) 
{ 
} 

public AuthenticationController(IFormsAuthentication formsAuth, 
    MembershipProvider provider) 
{ 
    this.FormsAuth = formsAuth; 
    this.Provider = provider; 
} 

在這種形式下,它應該是顯而易見的,僅僅需要兩個參數的構造分配類變量的參數值。參數構造函數(通常稱爲默認構造函數)簡單地創建使用默認FormsAuthProvider對象,它們經由構造鏈接指定一個新的對象。

1

問題1:??是null coalescing operator。 ?? ??運算符檢查表達式左側提供的值是否爲空,如果是,則返回表達式右側指示的替代值。

在您的情況下,它會檢查formsAuth是否爲空,並且如果爲空,則返回新的FormsAuthenticationWrapper()。

1

該??操作員說:「使用這個,除非它是空的,哪種情況下使用這個其他的東西」。

所以,這行代碼:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

是一樣的:

if (formsAuth != null) FormsAuth = formsAuth 
else FormsAuth = new FormsAuthenticationWrapper(); 
+0

但不會「這()」是派生類的構造函數,如果它的存在,而不是基類的構造函數?作爲「base()」的基類構造函數? – kervin 2009-06-22 13:13:17

+0

「調用基類構造函數」NO! this()不會**調用基類的構造函數! base()會這樣做。請修改並修復。 – dss539 2009-06-22 13:19:46

+0

@kervin&dss539 - Ouch,完全誤讀了這個問題。刪除了關於調用基類構造函數的誤導性內容。 – 2009-06-22 13:30:13

0

在回答Q2

它正在重載構造函數。

如果意味着調用

Foo() 

是與調用

Foo(null, null) 
0

問題1:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 
Provider = provider ?? Membership.Provider; 

是等於:

FormsAuth = (formsAuth == null ? new FormsAuthenticationWrapper() : formsAuth); 
Provider = (provider == null ? Membership.Provider : provider); 

問題2:

它只是將null傳遞給formsAuth和提供者構造函數參數。恕我直言,這不是好習慣。另一個沒有參數的構造函數會更適合。

編輯:這沒有意義。對不起,我很匆忙,並沒有真正意識到這是一個調用另一個構造函數的構造函數。

我沒有時間,現在來回答問題3,我會到後來......

0

問題1:??運營商只是說「採取一切是在我的左邊,如果它不是無效 - 如果是的話,採取我的權利「。所以,你的代碼:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

相當於

if (formsAuth != null) { 
    FormsAuth = formsAuth; 
} else { 
    FormsAuth 0 new FormsAuthenticationWrapper(); 
} 

問題2::this(null, null)語法速記 「構造繼承」(我命名...)。您的代碼

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; 
    } 
0

問題2

public AuthenticationController(): this(null, null) 
{ 
} 

的無參數的構造函數用於AuthenticationController將調用了一個IFormsAuthentication和的MembershipProvider構造函數,傳遞兩個空值(這是在no-param構造函數代碼塊中的任何代碼執行之前完成的)。 由於兩個參數的構造採用了空聚結(??)操作者指定的變量和傳遞的參數爲空,一個新的MembershipProvider與Membership.Provider對象一起使用。

尚未明確定義這個構造函數,默認無PARAM構造函數將被使用。如果創建一個新的AuthenticationController(不向構造函數傳遞任何參數),這可能會導致意外行爲,因爲成員變量不會被初始化。