Woher wissen Sie, was Sie beim Schreiben von Komponententests testen müssen? [geschlossen]


127

Mit C # benötige ich eine Klasse namens UserBenutzername, Passwort, aktives Flag, Vorname, Nachname, vollständiger Name usw.

Es sollte Methoden zum Authentifizieren und Speichern eines Benutzers geben. Schreibe ich nur einen Test für die Methoden? Und muss ich mir überhaupt Gedanken über das Testen der Eigenschaften machen, da es sich um .Nets Getter und Setter handelt?


Dieser Beitrag wird bei der Eingrenzung der umfassenderen Frage helfen : ernstestengineer.blogspot.com/2018/03/… Sie können diese Richtlinien verwenden, um Ihre Frage zu fokussieren
Lindsay Morsillo

Beachten Sie, dass Passwörter nicht als Klartext gespeichert werden sollten.
Herr Anderson

Antworten:


131

Viele gute Antworten darauf finden sich auch auf meiner Frage: " Beginn der TDD - Herausforderungen? Lösungen? Empfehlungen? "

Darf ich auch empfehlen, einen Blick auf meinen Blog-Beitrag zu werfen (der teilweise von meiner Frage inspiriert wurde), dazu habe ich ein gutes Feedback. Nämlich:

Ich weiß nicht, wo ich anfangen soll?

  • Neu anfangen. Denken Sie nur daran, Tests zu schreiben, wenn Sie neuen Code schreiben. Dies kann eine Überarbeitung des alten Codes oder eine völlig neue Funktion sein.
  • Fangen Sie einfach an. Gehen Sie nicht davonlaufen und versuchen Sie, sich mit einem Test-Framework vertraut zu machen und TDD-artig zu sein. Debug.Assert funktioniert gut. Verwenden Sie es als Ausgangspunkt. Es wird nicht mit Ihrem Projekt durcheinander gebracht oder Abhängigkeiten erstellt.
  • Fangen Sie positiv an. Sie versuchen, Ihr Handwerk zu verbessern, fühlen sich gut dabei. Ich habe viele Entwickler gesehen, die gerne stagnieren und keine neuen Dinge ausprobieren, um sich selbst zu verbessern. Sie tun das Richtige, denken Sie daran und es wird Ihnen helfen, nicht aufzugeben.
  • Bereite dich auf eine Herausforderung vor. Es ist ziemlich schwierig, mit dem Testen zu beginnen. Erwarten Sie eine Herausforderung, aber denken Sie daran - Herausforderungen können überwunden werden.

Testen Sie nur, was Sie erwarten

Ich hatte echte Probleme, als ich anfing, weil ich ständig da saß und versuchte, jedes mögliche Problem herauszufinden, das auftreten könnte, und dann versuchte, es zu testen und zu beheben. Dies ist ein schneller Weg zu Kopfschmerzen. Testen sollte ein echter YAGNI-Prozess sein. Wenn Sie wissen, dass ein Problem vorliegt, schreiben Sie einen Test dafür. Ansonsten kümmere dich nicht darum.

Testen Sie nur eine Sache

Jeder Testfall sollte immer nur eine Sache testen. Wenn Sie jemals feststellen, dass der Name des Testfalls „und“ enthält, machen Sie etwas falsch.

Ich hoffe das bedeutet, dass wir von "Getter and Setter" weitermachen können :)


2
"Wenn Sie wissen, dass es ein Problem gibt, schreiben Sie einen Test dafür. Andernfalls stören Sie sich nicht." Ich würde der Art und Weise, wie dies formuliert ist, nicht zustimmen. Ich hatte den Eindruck, dass Unit-Tests alle möglichen Ausführungspfade abdecken sollten.
Corin Blaikie

3
Während einige solche Dinge befürworten mögen, tue ich es persönlich nicht. Gut 90% meiner Kopfschmerzen kamen von dem Versuch, "alles" zu tun. Ich sage Test für das, was Sie erwarten (damit Sie wissen, dass Sie die richtigen Werte zurückbekommen), aber versuchen Sie nicht, alles herauszufinden. YAGNI.
Rob Cooper

4
Auch ich befürworte den Ansatz "Teste deine Bugs". Wenn wir alle unendlich viel Zeit und Geduld hätten, würden wir jeden möglichen Ausführungspfad testen. Aber wir tun es nicht, also müssen Sie Ihre Anstrengungen dort einsetzen, wo es die größte Wirkung haben wird.
Schwern

63

Testen Sie Ihren Code, nicht die Sprache.

Ein Unit-Test wie:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

ist nur nützlich, wenn Sie einen Compiler schreiben und die Wahrscheinlichkeit ungleich Null ist, dass Ihre instanceofMethode nicht funktioniert.

Testen Sie keine Dinge, auf deren Durchsetzung Sie sich auf die Sprache verlassen können. In Ihrem Fall würde ich mich auf Ihre Authentifizierungs- und Speichermethoden konzentrieren - und Tests schreiben, die sicherstellen, dass sie Nullwerte in einem oder allen dieser Felder ordnungsgemäß verarbeiten können.


1
Guter Punkt zu "Testen Sie das Framework nicht" - etwas, das ich auch verstanden habe, als ich neu in diesem Bereich war. + 1'ed :)
Rob Cooper

38

Dies brachte mich zum Testen von Einheiten und machte mich sehr glücklich

Wir haben gerade angefangen, Unit-Tests durchzuführen. Lange wusste ich, dass es gut sein würde, damit zu beginnen, aber ich hatte keine Ahnung, wie ich anfangen sollte und was noch wichtiger war, was ich testen sollte.

Dann mussten wir einen wichtigen Code in unser Buchhaltungsprogramm umschreiben. Dieser Teil war sehr komplex, da er viele verschiedene Szenarien beinhaltete. Der Teil, über den ich spreche, ist eine Methode zum Bezahlen von Verkaufs- und / oder Kaufrechnungen, die bereits in das Buchhaltungssystem eingegeben wurden.

Ich wusste einfach nicht, wie ich mit dem Codieren beginnen sollte, da es so viele verschiedene Zahlungsoptionen gab. Eine Rechnung könnte 100 US-Dollar betragen, aber der Kunde hat nur 99 US-Dollar überwiesen. Möglicherweise haben Sie Verkaufsrechnungen an einen Kunden gesendet, aber Sie haben auch bei diesem Kunden gekauft. Sie haben ihn also für 300 Dollar verkauft, aber für 100 Dollar gekauft. Sie können erwarten, dass Ihr Kunde Ihnen 200 US-Dollar zahlt, um den Restbetrag zu begleichen. Und was ist, wenn Sie für 500 US-Dollar verkauft haben, der Kunde Ihnen jedoch nur 250 US-Dollar zahlt?

Ich hatte also ein sehr komplexes Problem zu lösen, mit vielen Möglichkeiten, dass ein Szenario perfekt funktionieren würde, aber bei einer anderen Art von Invocie / Payment-Kombination falsch wäre.

Hier kamen Unit-Tests zum Einsatz.

Ich begann (innerhalb des Testcodes) eine Methode zu schreiben, um eine Liste von Rechnungen sowohl für Verkäufe als auch für Einkäufe zu erstellen. Dann habe ich eine zweite Methode geschrieben, um die tatsächliche Zahlung zu erstellen. Normalerweise würde ein Benutzer diese Informationen über eine Benutzeroberfläche eingeben.

Dann habe ich die erste Testmethode erstellt, bei der eine sehr einfache Zahlung einer einzelnen Rechnung ohne Zahlungsrabatte getestet wurde. Alle Aktionen im System würden ausgeführt, wenn eine Bankzahlung in der Datenbank gespeichert würde. Wie Sie sehen, habe ich eine Rechnung erstellt, eine Zahlung (eine Banküberweisung) erstellt und die Transaktion auf der Festplatte gespeichert. In meinen Behauptungen habe ich die richtigen Zahlen angegeben, die in der Banküberweisung und in der verknüpften Rechnung landen. Ich überprüfe nach der Transaktion die Anzahl der Zahlungen, die Zahlungsbeträge, den Rabattbetrag und den Restbetrag der Rechnung.

Nachdem der Test ausgeführt wurde, ging ich zur Datenbank und überprüfte noch einmal, ob das, was ich erwartet hatte, dort war.

Nachdem ich den Test geschrieben hatte, begann ich mit der Codierung der Zahlungsmethode (Teil der BankHeader-Klasse). In der Codierung habe ich mich nur mit Code beschäftigt, um den ersten Test zu bestehen. Ich habe noch nicht über die anderen, komplexeren Szenarien nachgedacht.

Ich habe den ersten Test ausgeführt und einen kleinen Fehler behoben, bis mein Test bestanden wurde.

Dann fing ich an, den zweiten Test zu schreiben, diesmal mit einem Zahlungsrabatt. Nachdem ich den Test geschrieben habe, habe ich die Zahlungsmethode geändert, um Rabatte zu unterstützen.

Beim Testen der Richtigkeit mit einem Zahlungsrabatt habe ich auch die einfache Zahlung getestet. Beide Tests sollten natürlich bestehen.

Dann arbeitete ich mich zu den komplexeren Szenarien hinunter.

1) Stellen Sie sich ein neues Szenario vor

2) Schreiben Sie einen Test für dieses Szenario

3) Führen Sie diesen einzelnen Test durch, um festzustellen, ob er bestanden wird

4) Wenn dies nicht der Fall wäre, würde ich den Code debuggen und ändern, bis er erfolgreich ist.

5) Während ich den Code änderte, führte ich alle Tests weiter aus

So gelang es mir, meine sehr komplexe Zahlungsmethode zu erstellen. Ohne Unit-Tests wusste ich nicht, wie ich mit dem Codieren beginnen sollte. Das Problem schien überwältigend. Beim Testen könnte ich mit einer einfachen Methode beginnen und sie Schritt für Schritt erweitern, mit der Gewissheit, dass die einfacheren Szenarien immer noch funktionieren würden.

Ich bin sicher, dass mir die Verwendung von Unit-Tests einige Tage (oder Wochen) an Codierung erspart hat und mehr oder weniger die Richtigkeit meiner Methode garantiert.

Wenn ich später an ein neues Szenario denke, kann ich es einfach zu den Tests hinzufügen, um zu sehen, ob es funktioniert oder nicht. Wenn nicht, kann ich den Code ändern, aber trotzdem sicherstellen, dass die anderen Szenarien immer noch ordnungsgemäß funktionieren. Dies spart Tage und Tage in der Wartungs- und Fehlerbehebungsphase.

Ja, selbst getesteter Code kann immer noch Fehler aufweisen, wenn ein Benutzer Dinge tut, an die Sie nicht gedacht haben oder die ihn daran gehindert haben

Im Folgenden sind nur einige Tests aufgeführt, die ich zum Testen meiner Zahlungsmethode erstellt habe.

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }

1
In Ihrem Unit-Test einen Fehler gefunden! Sie wiederholen diese Zeile, anstatt eine 2 in eine von ihnen aufzunehmen:Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
Ryan Peschel

2
Sie sagen: "Nachdem der Test ausgeführt wurde, ging ich zur Datenbank und überprüfte noch einmal, ob das, was ich erwartet hatte, dort war." Dies ist ein gutes Beispiel für einen Integrationstest zwischen Komponenten Ihres Systems - kein isolierter Komponententest für einen einzelnen Code.
JTech

2
Sie haben auch die Regel von mehr als einem Assert pro Test gebrochen.
Steve

13

Wenn sie wirklich trivial sind, sollten Sie nicht testen. ZB wenn sie so implementiert sind;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Wenn Sie andererseits etwas Kluges tun (wie das Ver- und Entschlüsseln des Passworts im Getter / Setter), testen Sie es.


10

Die Regel ist, dass Sie jede Logik testen müssen, die Sie schreiben. Wenn Sie bestimmte Funktionen in die Getter und Setter implementiert haben, sind sie meiner Meinung nach einen Test wert. Wenn sie nur einigen privaten Feldern Werte zuweisen, stören Sie sich nicht.


6

Diese Frage scheint eine Frage zu sein, wo man die Grenze zieht, welche Methoden getestet werden und welche nicht.

Die Setter und Getter für die Wertzuweisung wurden mit Blick auf Konsistenz und zukünftiges Wachstum erstellt und sehen voraus, dass sich der Setter / Getter später zu komplexeren Operationen entwickeln kann. Es wäre sinnvoll, Unit-Tests dieser Methoden durchzuführen, auch im Hinblick auf Konsistenz und zukünftiges Wachstum.

Die Zuverlässigkeit des Codes, insbesondere während Änderungen, um zusätzliche Funktionen hinzuzufügen, ist das Hauptziel. Ich bin mir nicht bewusst, dass jemals jemand entlassen wurde, weil er Setter / Getter in die Testmethode aufgenommen hat, aber ich bin mir sicher, dass es Leute gibt, die sich gewünscht haben, Methoden getestet zu haben, von denen sie zuletzt wussten, dass sie einfache Set / Get-Wrapper waren, aber das war nein länger der Fall.

Vielleicht hat ein anderes Mitglied des Teams die Set / Get-Methoden um Logik erweitert, die jetzt getestet werden muss, aber dann die Tests nicht erstellt hat. Aber jetzt ruft Ihr Code diese Methoden auf und Sie wissen nicht, dass sie sich geändert haben und eingehende Tests erfordern. Die Tests, die Sie in der Entwicklung und in der Qualitätssicherung durchführen, lösen den Fehler nicht aus, aber echte Geschäftsdaten am ersten Tag der Veröffentlichung auslösen.

Die beiden Teamkollegen werden nun darüber diskutieren, wer den Ball fallen gelassen und keine Unit-Tests durchgeführt hat, wenn das Set / verwandelt wird, um Logik aufzunehmen, die fehlschlagen kann, aber nicht durch einen Unit-Test abgedeckt wird. Der Teamkollege, der ursprünglich das Set / Gets geschrieben hat, wird es leichter haben, aus diesem Clean herauszukommen, wenn die Tests vom ersten Tag an auf dem einfachen Set / Gets implementiert wurden.

Meiner Meinung nach können ein paar Minuten "verschwendete" Zeit, die ALLE Methoden mit Unit-Tests abdeckt, auch triviale, Tage Kopfschmerzen und den Verlust von Geld / Ansehen des Unternehmens und den Verlust des Arbeitsplatzes einer Person ersparen.

Und die Tatsache, dass Sie triviale Methoden mit Komponententests abgeschlossen haben, kann dieser Junior-Teamkollege sehen, wenn er die trivialen Methoden in nicht triviale Methoden umwandelt und ihn auffordert, den Test zu aktualisieren, und jetzt ist niemand in Schwierigkeiten, weil der Fehler enthalten war von der Produktion zu erreichen.

Die Art und Weise, wie wir codieren, und die Disziplin, die sich aus unserem Code ergibt, können anderen helfen.


4

Eine weitere kanonische Antwort. Ich glaube, das von Ron Jeffries:

Testen Sie nur den Code, den Sie bearbeiten möchten.


3

Das Testen von Boilerplate-Code ist Zeitverschwendung, aber wie Slavo sagt, sollten Sie einen Test schreiben, der diese Funktionalität begleitet, wenn Sie Ihren Gettern / Setzern einen Nebeneffekt hinzufügen.

Wenn Sie eine testgetriebene Entwicklung durchführen, sollten Sie zuerst den Vertrag (z. B. die Schnittstelle) und dann die Tests schreiben, um diese Schnittstelle auszuführen, die die erwarteten Ergebnisse / das erwartete Verhalten dokumentiert. Schreiben Sie dann Ihre Methoden selbst, ohne den Code in Ihren Komponententests zu berühren. Nehmen Sie zum Schluss ein Tool zur Codeabdeckung und stellen Sie sicher, dass Ihre Tests alle Logikpfade in Ihrem Code ausführen.


3

Wirklich trivialer Code wie Getter und Setter, die kein zusätzliches Verhalten als das Setzen eines privaten Feldes haben, sind zu viel zu testen. In 3.0 hat C # sogar syntaktischen Zucker, bei dem sich der Compiler um das private Feld kümmert, sodass Sie das nicht programmieren müssen.

Normalerweise schreibe ich viele sehr einfache Tests, um das Verhalten zu überprüfen, das ich von meinen Klassen erwarte. Auch wenn es einfach ist, zwei Zahlen hinzuzufügen. Ich wechsle viel zwischen dem Schreiben eines einfachen Tests und dem Schreiben einiger Codezeilen. Der Grund dafür ist, dass ich dann den Code ändern kann, ohne befürchten zu müssen, dass ich Dinge kaputt gemacht habe, an die ich nicht gedacht habe.


Ich bin froh, dass Sie das KISS-Prinzip gut formuliert haben. Ich habe oft Tests, die buchstäblich wie 2-3 Codezeilen sind, wirklich kleine, einfache Tests. Leicht zu groken und schwer zu brechen :) + 1'ed
Rob Cooper

3

Sie sollten alles testen. Im Moment haben Sie Getter und Setter, aber eines Tages könnten Sie sie etwas ändern, vielleicht um eine Validierung durchzuführen oder etwas anderes. Die Tests, die Sie heute schreiben, werden morgen verwendet, um sicherzustellen, dass alles wie gewohnt funktioniert. Wenn Sie einen Test schreiben, sollten Sie Überlegungen wie "Im Moment ist es trivial" vergessen. In einem agilen oder testgetriebenen Kontext sollten Sie unter der Annahme eines zukünftigen Refactorings testen. Haben Sie auch versucht, wirklich seltsame Werte wie extrem lange Zeichenfolgen oder andere "schlechte" Inhalte einzugeben? Nun, Sie sollten ... niemals davon ausgehen, wie stark Ihr Code in Zukunft missbraucht werden kann.

Generell finde ich das Schreiben umfangreicher Benutzertests einseitig und anstrengend. Auf der anderen Seite erhalten Sie jedoch immer wertvolle Einblicke in die Funktionsweise Ihrer Anwendung und können einfache (und falsche) Annahmen verwerfen (z. B.: Der Benutzername ist immer weniger als 1000 Zeichen lang).


3

Für einfache Module, die möglicherweise in einem Toolkit oder einem Open-Source-Projekt landen, sollten Sie so viel wie möglich testen, einschließlich der trivialen Getter und Setter. Das, was Sie beachten möchten, ist, dass das Generieren eines Komponententests beim Schreiben eines bestimmten Moduls ziemlich einfach und unkompliziert ist. Das Hinzufügen von Gettern und Setzern ist minimaler Code und kann ohne viel Nachdenken gehandhabt werden. Sobald Ihr Code jedoch in einem größeren System abgelegt ist, können Sie durch diesen zusätzlichen Aufwand vor Änderungen im zugrunde liegenden System geschützt werden, z. B. vor Typänderungen in einer Basisklasse. Alles zu testen ist der beste Weg, um eine vollständige Regression zu erzielen.


2

Es tut nicht weh, Unit-Tests für Ihre Getter und Setter zu schreiben. Im Moment führen sie möglicherweise nur Feld-Get / Sets unter der Haube durch, aber in Zukunft haben Sie möglicherweise Validierungslogik oder Abhängigkeiten zwischen Eigenschaften, die getestet werden müssen. Es ist jetzt einfacher, es zu schreiben, während Sie darüber nachdenken, als daran zu denken, es nachzurüsten, wenn diese Zeit jemals kommt.


Nun, wenn Ihre Getter / Setter Unit-Tests benötigen, muss ihnen eine Logik zugeordnet sein. Das bedeutet, dass Logik in sie geschrieben werden muss. Wenn sie keine Logik haben, müssen keine Unit-Tests geschrieben werden.
Pop Catalin

2
Sein Punkt ist, dass Logik später zu ihnen hinzugefügt werden kann.
LegendLength

2

Wenn eine Methode nur für bestimmte Werte definiert ist, testen Sie im Allgemeinen auf Werte an und über der Grenze dessen, was akzeptabel ist. Mit anderen Worten, stellen Sie sicher, dass Ihre Methode das tut, was sie tun soll, aber nicht mehr . Dies ist wichtig, denn wenn Sie scheitern, möchten Sie frühzeitig scheitern.

Stellen Sie in Vererbungshierarchien sicher, dass Sie die LSP- Konformität testen .

Das Testen von Standard-Gettern und -Setzern scheint mir nicht sehr nützlich zu sein, es sei denn, Sie planen später eine Validierung.


2

Wenn Sie glauben, dass es kaputt gehen kann, schreiben Sie einen Test dafür. Normalerweise teste ich Setter / Getter nicht, aber sagen wir, Sie machen einen für User.Name, der Vor- und Nachnamen verkettet. Ich würde einen Test schreiben. Wenn also jemand die Reihenfolge für Nach- und Vornamen ändert, würde er es zumindest wissen er hat etwas geändert, das getestet wurde.


2

Die kanonische Antwort lautet: "Testen Sie alles, was möglicherweise kaputt gehen kann." Wenn Sie sicher sind, dass die Eigenschaften nicht beschädigt werden, testen Sie sie nicht.

Und wenn festgestellt wird, dass etwas kaputt ist (Sie finden einen Fehler), bedeutet dies natürlich, dass Sie es testen müssen. Schreiben Sie einen Test, um den Fehler zu reproduzieren, beobachten Sie, wie er fehlschlägt, beheben Sie den Fehler und beobachten Sie, wie der Test bestanden wird.


1

Wie ich Unit-Tests im Kontext der agilen Entwicklung verstehe, Mike, ja, müssen Sie die Getter und Setter testen (vorausgesetzt, sie sind öffentlich sichtbar). Das gesamte Konzept des Komponententests besteht darin, die Softwareeinheit, die in diesem Fall eine Klasse ist, als zu testen Black Box . Da die Getter und Setter von außen sichtbar sind, müssen Sie sie zusammen mit Authentifizieren und Speichern testen.


1

Wenn die Methoden Authentifizieren und Speichern die Eigenschaften verwenden, berühren Ihre Tests indirekt die Eigenschaften. Solange die Eigenschaften nur den Zugriff auf Daten ermöglichen, sollten keine expliziten Tests erforderlich sein (es sei denn, Sie streben eine 100% ige Abdeckung an).


1

Ich würde Ihre Getter und Setter testen. Abhängig davon, wer den Code schreibt, ändern einige Leute die Bedeutung der Getter / Setter-Methoden. Ich habe Variableninitialisierung und andere Validierung als Teil von Getter-Methoden gesehen. Um diese Art von Dingen zu testen, möchten Sie Unit-Tests, die diesen Code explizit abdecken.


1

Persönlich würde ich "alles testen, was brechen kann" und einfacher Getter (oder noch besser Auto-Eigenschaften) wird nicht brechen. Ich habe noch nie eine einfache Rückgabe fehlgeschlagen und daher nie einen Test für sie durchgeführt. Wenn die Getter Berechnungen oder eine andere Form von Aussagen enthalten, würde ich sicherlich Tests für sie hinzufügen.

Persönlich verwende ich Moq als Scheinobjekt-Framework und überprüfe dann, ob mein Objekt die umgebenden Objekte so aufruft, wie es sollte.


1

Sie müssen die Ausführung jeder Methode der Klasse mit UT abdecken und den Rückgabewert der Methode überprüfen. Dies schließt Getter und Setter ein, insbesondere wenn die Mitglieder (Eigenschaften) komplexe Klassen sind, die während ihrer Initialisierung eine große Speicherzuweisung erfordern. Rufen Sie den Setter zum Beispiel mit einer sehr großen Zeichenfolge (oder etwas mit griechischen Symbolen) auf und überprüfen Sie, ob das Ergebnis korrekt ist (nicht abgeschnitten, die Codierung ist gut usw.).

Bei einfachen ganzen Zahlen gilt das auch - was passiert, wenn Sie lange statt ganze Zahlen übergeben? Das ist der Grund, warum du UT schreibst :)


1

Ich würde die tatsächliche Einstellung der Eigenschaften nicht testen. Ich wäre mehr besorgt darüber, wie diese Eigenschaften vom Verbraucher bevölkert werden und womit sie sie bevölkern. Bei jedem Test müssen Sie die Risiken mit der Zeit / den Kosten des Tests abwägen.


1

Sie sollten "jeden nicht trivialen Codeblock" so weit wie möglich mithilfe von Komponententests testen.

Wenn Ihre Eigenschaften trivial sind und es unwahrscheinlich ist, dass jemand einen Fehler einführt, sollte es sicher sein, sie nicht einem Unit-Test zu unterziehen.

Ihre Methoden Authenticate () und Save () sehen aus wie gute Kandidaten für Tests.


1

Idealerweise hätten Sie Ihre Komponententests durchgeführt, als Sie die Klasse geschrieben haben. So sollen Sie es machen, wenn Sie Test Driven Development verwenden. Sie fügen die Tests hinzu, während Sie jeden Funktionspunkt implementieren, und stellen sicher, dass Sie auch die Randfälle mit Test abdecken.

Das anschließende Schreiben der Tests ist viel schmerzhafter, aber machbar.

Folgendes würde ich in Ihrer Position tun:

  1. Schreiben Sie eine Reihe grundlegender Tests, mit denen die Kernfunktion getestet wird.
  2. Holen Sie sich NCover und führen Sie es bei Ihren Tests aus. Ihre Testabdeckung wird zu diesem Zeitpunkt wahrscheinlich bei etwa 50% liegen.
  3. Fügen Sie weitere Tests hinzu, die Ihre Randfälle abdecken, bis Sie eine Abdeckung von etwa 80% -90% erhalten.

Dies sollte Ihnen eine Reihe von Unit-Tests bieten, die als guter Puffer gegen Regressionen dienen.

Das einzige Problem bei diesem Ansatz ist, dass Code entworfen werden muss , dass er auf diese Weise getestet werden kann. Wenn Sie frühzeitig Kopplungsfehler gemacht haben, können Sie nicht so einfach eine hohe Abdeckung erzielen.

Aus diesem Grund ist es sehr wichtig, die Tests zu schreiben, bevor Sie den Code schreiben. Es zwingt Sie, Code zu schreiben, der lose gekoppelt ist.


1

Testen Sie nicht offensichtlich funktionierenden Code (Boilerplate). Wenn Ihre Setter und Getter also nur "propertyvalue = value" und "return propertyvalue" sind, macht es keinen Sinn, sie zu testen.


1

Sogar get / set kann seltsame Konsequenzen haben, abhängig davon, wie sie implementiert wurden. Daher sollten sie als Methoden behandelt werden.

Bei jedem dieser Tests müssen Parametersätze für die Eigenschaften angegeben werden, wobei sowohl akzeptable als auch nicht akzeptable Eigenschaften definiert werden, um sicherzustellen, dass die Aufrufe in der erwarteten Weise zurückkehren / fehlschlagen.

Sie müssen auch Sicherheitslücken kennen, beispielsweise eine SQL-Injection, und diese testen.

Ja, Sie müssen sich also Gedanken über das Testen der Eigenschaften machen.


1

Ich halte es für dumm, Getter und Setter zu testen, wenn sie nur eine einfache Operation durchführen. Persönlich schreibe ich keine komplexen Unit-Tests, um ein Nutzungsmuster abzudecken. Ich versuche, genügend Tests zu schreiben, um sicherzustellen, dass ich das normale Ausführungsverhalten und so viele Fehlerfälle wie möglich behandelt habe. Ich werde weitere Unit-Tests als Antwort auf Fehlerberichte schreiben. Ich verwende Unit-Tests, um sicherzustellen, dass der Code den Anforderungen entspricht, und um zukünftige Änderungen zu vereinfachen. Ich bin viel eher bereit, Code zu ändern, wenn ich weiß, dass ein Test fehlschlägt, wenn ich etwas kaputt mache.


1

Ich würde einen Test für alles schreiben, für das Sie Code schreiben, der außerhalb der GUI-Oberfläche getestet werden kann.

Normalerweise jede Logik, die ich schreibe und die eine Geschäftslogik enthält, die ich in einer anderen Schicht oder Geschäftslogikschicht platziere.

Dann ist es einfach, Tests für alles zu schreiben, was etwas tut.

Schreiben Sie im ersten Durchgang einen Komponententest für jede öffentliche Methode in Ihre "Business Logic Layer".

Wenn ich eine Klasse wie diese hätte:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

Das erste, was ich tun würde, bevor ich Code schreibe, in dem Wissen, dass ich diese Aktionen ausführen muss, ist, mit dem Schreiben von Komponententests zu beginnen.

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

Schreiben Sie Ihre Tests, um den Code zu validieren, den Sie geschrieben haben, um etwas zu tun. Wenn Sie eine Sammlung von Dingen durchlaufen und an jedem etwas ändern, schreiben Sie einen Test, der dasselbe tut, und bestätigen Sie, dass dies tatsächlich passiert ist.

Es gibt viele andere Ansätze, die Sie verfolgen können, nämlich Behavoir Driven Development (BDD), die aufwändiger sind und kein guter Ausgangspunkt für Ihre Unit-Testing-Fähigkeiten sind.

Die Moral der Geschichte lautet also: Testen Sie alles, was Sie beunruhigt, lassen Sie die Unit-Tests bestimmte Dinge testen, die klein sind. Viele Tests sind gut.

Halten Sie Ihre Geschäftslogik außerhalb der Benutzeroberfläche, damit Sie problemlos Tests für sie schreiben können, und Sie werden gut.

Ich empfehle TestDriven.Net oder ReSharper, da beide problemlos in Visual Studio integriert werden können.


1

Ich würde empfehlen, mehrere Tests für Ihre Authentifizierungs- und Speichermethoden zu schreiben. Zusätzlich zum Erfolgsfall (bei dem alle Parameter angegeben sind, alles richtig geschrieben ist usw.) ist es gut, Tests für verschiedene Fehlerfälle durchzuführen (falsche oder fehlende Parameter, gegebenenfalls nicht verfügbare Datenbankverbindungen usw.). Ich empfehle Pragmatic Unit Testing in C # mit NUnit als Referenz.

Wie andere angegeben haben, sind Unit-Tests für Getter und Setter übertrieben, es sei denn, Ihre Getter und Setter enthalten eine bedingte Logik.


1

Während es möglich ist, richtig zu erraten, wo Ihr Code getestet werden muss, denke ich im Allgemeinen, dass Sie Metriken benötigen, um diese Vermutung zu stützen. Aus meiner Sicht gehen Unit-Tests Hand in Hand mit Code-Coverage-Metriken.

Code mit vielen Tests, aber einer kleinen Abdeckung wurde nicht gut getestet. Das heißt, Code mit 100% Abdeckung, aber ohne Testen der Grenz- und Fehlerfälle ist auch nicht großartig.

Sie möchten ein Gleichgewicht zwischen hoher Abdeckung (mindestens 90%) und variablen Eingabedaten.

Denken Sie daran, auf "Müll in" zu testen!

Ein Unit-Test ist auch kein Unit-Test, es sei denn, er prüft auf einen Fehler. Unit-Tests, die keine Asserts haben oder mit bekannten Ausnahmen gekennzeichnet sind, testen einfach, ob der Code beim Ausführen nicht stirbt!

Sie müssen Ihre Tests so gestalten, dass sie immer Fehler oder unerwartete / unerwünschte Daten melden!


1

Es macht unseren Code besser ... Punkt!

Eine Sache, die wir Softwareentwickler bei der testgetriebenen Entwicklung vergessen, ist der Zweck unserer Aktionen. Wenn ein Komponententest geschrieben wird, nachdem der Produktionscode bereits vorhanden ist, sinkt der Wert des Tests erheblich (geht jedoch nicht vollständig verloren).

Im wahren Sinne für Unit-Tests dienen diese Tests nicht in erster Linie dazu, mehr von unserem Code zu "testen". oder um eine um 90% -100% bessere Codeabdeckung zu erzielen. Dies sind alles Nebeneffekte, wenn Sie die Tests zuerst schreiben. Der große Gewinn ist, dass unser Produktionscode aufgrund des natürlichen Prozesses von TDD viel besser geschrieben werden kann.

Um diese Idee besser zu kommunizieren, kann Folgendes beim Lesen hilfreich sein:

Die fehlerhafte Theorie der Komponententests
Zielgerichtete Softwareentwicklung

Wenn wir der Meinung sind, dass das Schreiben von mehr Komponententests uns dabei hilft, ein Produkt mit höherer Qualität zu erhalten, leiden wir möglicherweise unter einem Frachtkult der testgetriebenen Entwicklung.


Ich bin mit der Behauptung nicht einverstanden, dass Komponententests keinen Wert haben, nachdem der Produktionscode bereits vorhanden ist. Solche Behauptungen berücksichtigen nicht ihre Nützlichkeit bei der Replikation von Fehlerbedingungen in der Produktion oder beim Verständnis von Code, der von einem früheren Entwickler oder Team geerbt wurde.
Scott Lawrence

Ich bin möglicherweise falsch rübergekommen. Ich habe nicht gemeint, dass Unit-Tests keinen Wert haben, nachdem der Produktionscode vorhanden ist. Ihr Wert sinkt jedoch. Der größte Vorteil von Unit-Tests liegt in der Magie, die entsteht, wenn wir sie unsere Produktionsentwicklung vorantreiben lassen.
Scott Saad
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.