2009-06-04 17 views
5

Ich bin sehr neu zu TDD und ich habe Probleme mit einem meiner Komponententests. Ich kann einfach nicht verstehen, was ich als nächstes tun soll. . :(Ich bin zu Unit-Test versucht, einen Dienst von mir genannten Account und teste ich eine Methode DoLogin (Benutzername, Passwort) genannt Hier einige Beispiel-Code:Unit Testen einer Anmeldung in ASP.NET

[Test] 
    public void User_With_Correct_Username_And_Pass_Should_Login_Successfully() 
    { 
     // Arrange 
     var accountService = new AccountService(); 

     // Act 
     bool result = accountService.DoLogin("test", "test"); 

     // Assert 
     Assert.IsTrue(result); 
    } 

    public class AccountService : IAccountService 
    { 
     public bool DoLogin(string username, string password) 
     { 
     if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) 
      return false; 

     return true; 
     } 
    } 

dieser Test Vergangenheiten So aber jetzt, was zu tun Ich tue ?! Wie teste ich wirklich, ob ein gültiger Login aufgetreten ist? Muss ich einen Integrationstest implementieren und den Login gegen eine reale oder in-Memory DB testen? Tut mir leid, wenn ich Dinge total falsch mache. Ich hoffe wirklich eins Tag hinunter dieses TDD Zeug zu bekommen. Dank

Antwort

14

Ihre Erfahrungen Mine sehr ähnlich ist, ausgehend. Während ich auf TDD verkauft werde und nichts anders machen würde, verstehe ich Ihre Verwirrung. Es ist wichtig, daran zu denken, dass TDD eine Designphilosophie ist. Davon abgesehen denke ich, dass ich Ihnen helfen kann, einige Ihrer Frustrationen zu klären.

  1. Sie zunächst darüber nachzudenken, was Sie versuchen, nicht auf individuellem Testniveau zu erreichen, aber was Sie zu tun versuchen. Wenn Ihre Aufgabe (User Story) darin besteht, einige Anmeldeinformationen zu erfassen und den aktuellen Benutzer basierend auf diesen Anmeldeinformationen zu authentifizieren, starten Sie von dort aus und arbeiten sich nach unten. Sie scheinen in dieser Richtung zu gehen, nur zu den nächsten Schritten stecken

  2. Wenn auf einem individuellen Test arbeiten, denken Sie an es in Bezug auf expected behavior anstatt nur einige Ein- und Ausgänge zu überprüfen. Stellen Sie sich diese Komponente vor und schreiben Sie einfach eine Codezeile so, wie Sie sie schreiben möchten. Lassen Sie diesen Teil helfen, die Schnittstelle/den Vertrag Ihres Dienstes zu steuern. Sie müssen sich die Frage stellen: "Wenn ich diese Methode nennen würde, wie würde ich wissen, dass sie funktioniert hat? Was würde ich davon erwarten?" Dies wird bestimmen, welche Art von Behauptungen Sie machen müssen.

  3. Bestimmen Sie, was Ihre externen Abhängigkeiten sind, und utilize abstractions instead (Abhängigkeit Inversion-Prinzip). Wenn diese Abhängigkeiten etwas sind, was Sie als Teil Ihrer Verhaltensüberprüfung interessieren, dann verwenden Sie dependency injection, so dass Sie einen mock in Ihrem Test verwenden können.

  4. Immer, immer, folgen Sie immer dieser Reihenfolge [Schreiben Sie Ihren Test, beobachten Sie es scheitern, Code zu übergeben, Refactor]. LERNEN SIE VON MEINEN FEHLERN !!! Vertrau mir, das ist nicht verhandelbar. Andernfalls können Sie TDD Ihre Probleme vorwerfen, wenn es nicht ordnungsgemäß eingesetzt wird.

Ok, also das alles zusammen mit Ihrem Beispiel setzen, und einige schön test cases from lance zur Verfügung gestellt, könnten wir so etwas tun:

[Test] 
public void ShouldAuthenticateValidUser() 
{ 
    IMyMockDa mockDa = new MockDataAccess(); 
    var service = new AuthenticationService(mockDa); 

    mockDa.AddUser("Name", "Password"); 

    Assert.IsTrue(service.DoLogin("Name", "Password")); 

    //Ensure data access layer was used 
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled); 
} 

[Test] 
public void ShouldNotAuthenticateUserWithInvalidPassword() 
{ 
    IMyMockDa mockDa = new MockDataAccess(); 
    var service = new AuthenticationService(mockDa); 

    mockDa.AddUser("Name", "Password"); 

    Assert.IsFalse(service.DoLogin("Name", "BadPassword")); 

    //Ensure data access layer was used 
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled); 
} 

Ok, so gibt es eine Menge los dort, und vielleicht viel zu erforschen. Sie können jedoch beginnen zu sehen, wie es möglich ist, gründliche Tests mit besserem Design durchzuführen. In den obigen Beispielen ist es wichtig zu beachten, dass das Mock-Objekt benutzerdefiniert gewürfelt wird, aber Sie müssen nicht durch all diese Schmerzen gehen. Es gibt viele Mocking Frameworks da draußen. Zum Beispiel mit RhinoMocks, würde Ihr Test wie folgt aussehen:

[Test] 
public void ShouldAuthenticateValidUser() 
{ 
    var mockRepo = new MockRepository(); 
    var mockDa = mockRepo.DynamicMock<IMyMockDa>(); 

    var service = new AuthenticationService(mockDa); 

    using(mockRepo.Record()) 
    { 
     //I realize this is a terrible method and should not exist if you 
     // care about security, but for demonstration purposes... 
     Expect.Call(mockDa.GetPassword("User")).Return("Password"); 
    } 
    using(mockRepo.Playback()) 
    { 
     Assert.IsTrue(service.DoLogin("User", "Password")); 
    } 
} 

Dinge die manuelle Art und Weise zu tun, zum ersten Mal verwendet, so dass Sie die Konzepte verstehen und dann weiterziehen, um ein Framework. Wütend! Viele Informationen, aber wie Sie sehen können, ist TDD eine komplette Design-Philosophie. Es wird jedoch sauberer Code, besseres Design und weniger Fehler führen.

+1

Vielen Dank, dass Sie sich die Zeit genommen haben, dies zu schreiben! Ich schätze es sehr. Du hast viele gute Sachen gesagt und es wird wahrscheinlich eine Weile dauern, bis ich alles verstanden habe. Du hast recht, dass ich mich daran gewöhnen muss, anders zu denken, wenn ich TDD mache. Hoffentlich wird meine Verwirrung eines Tages vorüber sein, aber das wird nur Zeit brauchen. Danke noch einmal! – CalebHC

+0

Es hat lange gedauert, bis ich diesen "Ah Ha" -Moment hatte, aber jetzt bin ich total bekehrt. Ich würde Sie ermutigen, einen anderen SO-Beitrag zu lesen, den ich über TDD machte: http://stackoverflow.com/questions/106800/unit-testing-guidelines/106813#106813 – Josh

+1

Das wackelige Rendering, das Sie sahen, ist ein bekannter Fehler mit alten Antworten - Sie können dies für jede Antwort (nicht nur für Ihre eigene) korrigieren, indem Sie eine Bearbeitung einreichen, wodurch die Antwort erneut gerendert wird. Dies erklärt auch, warum es gut aussieht, wenn Sie den Editor zum ersten Mal aufrufen. Ich habe die Formatierung hier geändert, aber Sie können auch eine Stub-Bearbeitung senden und sie rückgängig machen, und die Antwort wird trotzdem erneut gerendert. – BoltClock

0

Sie einen Test haben soll, dass ein ungültiger Benutzername oder Passwort ungültig verursacht DoLogin() zum scheitern verurteilt.

Da der Namen der Funktion, (DoLogin() statt CheckLogin()) würde ich denken, dass die Funktion auch einige Nebeneffekte haben sollte. Der Test sollte diesen Seiteneffekt überprüfen. Wirklich zu klären, was das ist, bevor jemand klären kann, wie es verifiziert werden soll.

1

Übergeben Sie Ihre gültigen und ungültigen Anmeldeinformationen an DoLogin, und vergleichen Sie dann die Ergebnisse mit Ihren Erwartungen. Versuchen Sie, sich jede mögliche (gelesene: sinnvolle) Kombination/Eingabe der Parameter "Benutzername" und "Passwort" vorzustellen, die der Benutzer zur Verfügung stellt, und erstellen Sie für jeden einen Test.

Wenn Sie an Ihre Geschäftslogik von DoLogin glauben, definieren wir einen "gültigen" Benutzernamen (und ein "gültiges" Passwort) als alles, was belegt ist. Fair genug, um der Diskussion willen.

Einige einfache Tests in den Sinn kommen:

Login_With_Null_UserName_Fails() 
Login_With_Populated_UserName_Succeeds() 
Login_With_Empty_UserName_Fails() 
Login_With_Null_Password_Fails() 
Login_With_Populated_Password_Succeeds() 
Login_With_Empty_Password_Fails() 

Oder betrachten Kombinationen:

Login_With_Null_UserName_And_Populated_Password_Fails() 
Login_With_Populated_UserName_And_Populated_Password_Succeeds() 
Login_With_Empty_UserName_And_Null_Password_Fails() 
etc 
etc 
+0

Cool, danke. Nachdem ich meine Testliste für DoLogin erschöpft habe, was ist dann mein nächster Schritt? Teste ich dann wirklich den Login gegen eine DB? – CalebHC

+0

Wenn Sie der Meinung sind, dass ein ausreichendes Risiko besteht, Ihre Parameter zu senden und die korrekten Ergebnisse von Ihren gespeicherten Prozeduren zu erhalten, dann sind Sie sicher! Tests helfen, das Risiko zu verringern und den Code zu verbessern. Ich empfehle Tests überall dort, wo Sie beide Möglichkeiten erwarten. – lance