2009-06-22 20 views
2

Ich versuche Unit-Tests zu lernen. Ich versuche, einige Membership Sachen zu testen, die ich in asp.net mvc 1.0 mache. Ich bin einem Buch über MVC gefolgt und ich bin verwirrt über einige Sachen, die hoffentlich jemand für mich aufräumen kann.Brauchen Sie Hilfe, diesen Code zu verstehen

Ich benutze Nunit und Moq für meine Frameworks.

Frage 1:

public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider) 
     { 
      FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 
      Provider = provider ?? Membership.Provider; 
     } 

Ich bin ein bisschen verwirrt, was "??" habe ich es vorher nie wirklich gesehen. Ich weiß nicht einmal, was hier wirklich passiert. Wie sie die Schnittstelle übergeben und dann "??" Mark passiert und macht einen neuen FormsAuthenticationWraper?

Frage 2.

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

Ich weiß, das der Standard-Konstruktor ist, aber ich bin nicht sicher, warum ": diese (null, null)" tut.

Wie funktioniert es? und was ist das auch? Und obendrüber warum kann das nicht einfach ausgelassen werden? Und kleben Sie einfach den Standardkonstruktor so wie er ist.

Frage 3.

Im Buch (asp.net Mvc 1.0 schnell) es spricht darüber, wie es ziemlich viel Arbeit zur Umsetzung der Memembership Anbieter eine Menge Arbeit wäre wäre. Daher verwenden sie das Moq-Mockup-Framework, um das Leben einfacher zu machen.

Jetzt ist meine Frage, sie verwenden nicht den Moq auf der "FormsAuthentication". Sie machen stattdessen eine Schnittstelle

public interface IFormsAuthentication 
     { 
      void SetAuthCookie(string userName, bool createPersistentCookie); 
      void SignOut(); 


     } 

Dann einen Wrapper machen

public class FormsAuthenticationWrapper: IFormsAuthentication { public void SetAuthCookie (string username, bool createPersistentCookie) { FormsAuthentication.SetAuthCookie (USERNAME- createPersistentCookie); } public void SignOut() { FormsAuthentication.SignOut(); }

} 

Dann endlich eine Eigenschaft

public IFormsAuthentication FormsAuth 
     { 
      get; 
      private set; 
     } 

Wo, wie mit der Mitgliedschaft sie nur

public static MembershipProvider Provider { get haben; privates Set; }

Ich bin nicht sicher, obwohl, was die Sachen zu ändern. Wie würde ich diese Linie auch ändern?

FormsAuth = FormulareAuth ?? neu FormsAuthenticationWrapper();

Ich habe auch versucht, eine andere Methode in die FormsAuthentication Interface und Wrapper hinzuzufügen.

public void RedirectFromLoginPage (string username, bool createPersistentCookie) { FormsAuthentication.RedirectFromLoginPage (USERNAME- createPersistentCookie); }

Noch bin ich nicht sicher, was passiert, aber mein Komponententest schlägt immer fehl, egal was ich versuche, um es zu beheben.

 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] 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(); 

    } 

Tatsächlich kommt immer wieder auf null zurück. Ich habe versucht, ViewResult, RedirectResult und RedirectToRouteResult, aber jeder kommt zurück Null. So bin ich nicht sicher, warum dies geschieht, da ich es seltsam finden, dass erste

     FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe); 

die Ansicht nicht stoppen und beginnt zu umleiten. Ich dachte zuerst, sobald es diese Zeile trifft, ist es wie eine Rückkehranweisung und das ist es wird kein anderer Code ausgeführt, aber es scheint nicht der Fall zu sein, also bin ich nicht sicher, ob dies das Problem sein könnte.

Danke

+1

Sie sollten Ihre Fragen wahrscheinlich in separaten Beiträgen aufteilen. Frage 1 und 2 sind verwandt und könnten einen Beitrag darstellen, aber Frage 3 sollte höchstwahrscheinlich für sich allein stehen. –

+0

Frage 3 ist mehr als eine Frage wirklich –

Antwort

11

Frage 1

Die ?? die null-coalescing operator genannt wird, und ist eine sehr nützliche Funktion von Ab C# 2.0.

In Ihrem Fall

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

bedeutet einfach "formsAuth-FormsAuth zugewiesen werden, wenn es null ist, in welchem ​​Fall new FormsAuthenticationWrapper() zuweisen". Es ist im Grunde eine Möglichkeit, Null-Referenzen in Ihrem Code zu verhindern. Sie können für die folgende Bedingung als Abkürzung davon denken auch:

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

Frage 2

Die Verwendung von this(null, null)constructor chaining genannt wird.All dies bedeutet, dass der Konstruktor in der gleichen Klasse (also this, im Gegensatz zu base für die Elternklasse), der zwei Parameter akzeptiert, aufgerufen werden sollte, bevor der Rumpf des Konstruktors ausgeführt wird.

Das Überladen von Konstruktoren ist eine gängige Praxis, um es dem Entwickler zu erleichtern, neue Objekte zu erstellen, wenn sie nur die Standardeigenschaften/-einstellungen verwenden möchten.

Frage 3

Wie andere erwähnt haben, das gehört eigentlich als eine separate Frage. Im Gegensatz zu den vorherigen beiden ist es viel spezifischer für den Kontext/Ihren Code als für die Sprachfunktionen von C#.

aktualisiert

Ok, was ich jetzt eigentlich neu geschrieben, die beiden Konstrukteure hier getan wird, da ich sie in einer anderen (praktisch gleichwertig) Form denken setzen könnte etwas klarer sein, und ist wahrscheinlich besser zu Designpraxis . Der Nullkoaleszenzoperator ist hier nicht notwendig.

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

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

In dieser Form sollte es offensichtlich sein, dass der Konstruktor, der zwei Parameter nimmt einfach die Klassenvariablen auf die Werte der Argumente zuweist. Der parameterlosen Konstruktor (oft das Standard Konstruktor aufgerufen) erstellt einfach ein neues Objekt mit den StandardFormsAuth und Provider Objekten, die über Konstruktorverkettung angegeben sind.

+0

Hmm, ok, es macht mehr Sinn. Mit dem Standardkonstruktor erbt es Sachen von der Steuerung richtig? (Ich bin nicht sicher, was genau geerbt wird, obwohl). Ich weiß nicht, ob ich jemals in einer Million Jahren dieses Zeug tun könnte lol. Ich frage mich immer noch, wann würde der Fall sein, dass FormsAuth null wäre? Ich sehe das nicht. Ich werde auch eine neue Frage für Frage 3 – chobo2

+0

@ chobo2: Siehe meinen aktualisierten Beitrag. – Noldorin

1

Frage 1: ?? ist die null coalescing operator. Das ?? Der Operator prüft, ob der auf der linken Seite des Ausdrucks angegebene Wert Null ist, und gibt in diesem Fall einen anderen Wert zurück, der auf der rechten Seite des Ausdrucks angegeben ist.

In Ihrer Situation überprüft es, ob formsAuth null ist, und gibt ein neues FormsAuthenticationWrapper() zurück, wenn es null ist.

1

Die ?? Der Operator sagt "benutze das, es sei denn, es ist null, es ist der Fall, der diese andere Sache benutzt".

Also, diese Codezeile:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

ist das gleiche wie:

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

Aber wäre "this()" nicht der abgeleitete Klassenkonstruktor, wenn er existiert und nicht der Basisklassenkonstruktor? Wo als "base()" der Basisklassenkonstruktor sein? – kervin

+0

"den Basisklassenkonstruktor aufrufen" NEIN! this() ruft ** NOT ** den Basisklassenkonstruktor auf! base() macht das. Bitte bearbeiten und korrigieren. – dss539

+0

@kervin & dss539 - Autsch, völlig falsch verstanden die Frage. Das irreführende Zeug zum Aufruf des Basisklassenkonstruktors wurde entfernt. –

0

In Antwort auf Q2

Es den Konstruktor zu überlasten.

Wenn bedeutet, dass

Foo() 

Aufruf der gleiche ist wie der Aufruf von

Foo(null, null) 
0

Frage 1:

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

ist gleich zu:

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

Frage 2:

Es übergibt nur NULL an beide FormenArc und Provider Konstruktor Argumente. Es ist keine gute Übung IMHO. Ein anderer Konstruktor ohne Argumente wäre besser geeignet.

EDIT: Das macht keinen Sinn. Entschuldigung, ich hatte es eilig und habe nicht wirklich gemerkt, dass es ein Konstruktor ist, der einen anderen Konstruktor aufruft.

Ich habe keine Zeit Frage 3 jetzt zu beantworten, werde ich auf diese später bekommen ...

+0

Ihre Antwort zu Frage 2 ist etwas aus - es ist nicht * nur * das gleiche wie das Hinzufügen eines anderen Konstruktors. Wenn Sie die Konstruktoren wie in den OP-Beispielen verketten, werden * beide * Konstruktoren tatsächlich ausgeführt. In diesem Fall ist einer zufällig leer ... –

+0

"Es ist keine gute Übung", weil ...? – dss539

0

Frage 1: Der ?? Bediener einfach sagt „nehmen, was zu meiner Linken ist, wenn es ist nicht null - wenn es ist, nimm, was auch immer rechts von mir ist ".So Ihr Code:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

entspricht

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

Frage 2: Die :this(null, null) Syntax ist eine Abkürzung für "Konstruktor Vererbung" (meine Namensgebung ...). Ihr Code

public AuthenticationController(): this(null, null) 
    { 
    } 
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider) 
    { 
     FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 
     Provider = provider ?? Membership.Provider; 
    } 

entspricht

public AuthenticationController() 
    { 
     FormsAuth = new FormsAuthenticationWrapper(); 
     Provider = Membership.Provider; 
    } 
public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider) 
    { 
     FormsAuth = formsAuth; 
     Provider = provider; 
    } 
+0

ic hmm Ich mag deinen Weg besser, es macht mehr Sinn auf der Fledermaus und macht das gleiche, richtig? – chobo2

+0

Wie Sie in Noldorins Antwort sehen können, sind die Beispiele für Frage 2 nur in diesem speziellen Beispiel äquivalent, aber nicht notwendigerweise. –

0

Frage 2

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

Der kein Parameter Konstruktor für AuthenticationController den Konstruktor aufrufen, die eine IFormsAuthentication und MembershipProvider nimmt, vorbei an zwei Null-Werte (dies wird durchgeführt, bevor irgendein Code in dem No-Param-Konstruktor-Codeblock ausgeführt wird). Da der Konstruktor für zwei Argumente den Operator null-coalescing (??) verwendet, um die Variablen zuzuweisen, und die übergebenen Argumente null sind, wird ein neuer MembershipProvider zusammen mit dem Membership.Provider-Objekt verwendet.

Wäre dieser Konstruktor nicht explizit definiert worden, wäre der Standard-Konstruktor no-param verwendet worden. Dies könnte zu einem unerwarteten Verhalten führen, wenn ein neuer AuthenticationController erstellt wurde (ohne Argumente an den Konstruktor zu übergeben), da die Elementvariablen nicht initialisiert wurden.

Verwandte Themen