Frage

Um mein Team schreibt prüfbaren Code zu helfen, kam ich mit dieser einfachen Liste der besten Praktiken für unsere C # Codebasis mehr prüfbar zu machen. (Einige der Punkte beziehen sich auf Einschränkungen von Rhino Mocks, ein Mockframework für C #, aber die Regeln kann allgemeiner als auch anzuwenden.) Hat jemand irgendwelche Best Practices, die sie folgen?

die Testbarkeit des Codes zu maximieren, diese Regeln befolgen:

  1. zunächst den Test schreiben, dann wird der Code Grund:.. Dadurch wird sichergestellt, dass Sie überprüfbaren Code schreiben und dass jede Zeile Code werden Tests für sie geschrieben

  2. Konstruktionsklassen Dependency Injection mit Grund:.. Sie können nicht verspotten oder testen, was nicht gesehen werden kann

  3. Separate UI-Code von seinem Verhalten unter Verwendung von Model-View-Controller-oder Model-View-Presenter . Grund: Ermöglicht die Geschäftslogik getestet werden, während die Teile, die nicht getestet werden können (die UI) minimiert wird.

  4. Schreiben Sie nicht statische Methoden oder Klassen . Grund:. Statische Methoden sind schwierig oder unmöglich zu isolieren und Rhino Mocks ist nicht in der Lage, sie zu verspotten

  5. .
  6. Programm off-Schnittstellen, keine Klassen Grund: Über Schnittstellen verdeutlicht die Beziehungen zwischen Objekten. Eine Schnittstelle soll einen Dienst definieren, die ein Objekt von seiner Umgebung benötigt. Außerdem können Schnittstellen leicht verspotten mit Rhino Mocks und anderen spöttischen Frameworks.

  7. Isolieren Sie externe Abhängigkeiten . Grund:. Ungelöste externe Abhängigkeiten können nicht getestet werden

  8. Mark als virtuelle Methoden wollen Sie spotten . Grund: Rhino Mocks nicht in der Lage ist, nicht-virtuelle Methoden zu verspotten

  9. .
War es hilfreich?

Lösung

Auf jeden Fall eine gute Liste. Hier sind ein paar Gedanken dazu:

  

Schreiben Sie den Test zuerst, dann der Code.

Ich bin damit einverstanden, auf einem hohen Niveau. Aber, würde ich etwas konkreter: „einen Test schreibt zuerst, dann schreiben gerade genug Code, um den Test zu bestehen, und wiederholen.“ Ansonsten würde ich Angst, dass meine Unit-Tests mehr aussehen würde wie Integration oder Abnahmen.

  

Konstruktionsklassen mit Dependency Injection.

Einverstanden. Wenn ein Objekt seine eigene Abhängigkeiten schafft, haben Sie keine Kontrolle über sie. Inversion of Control / Dependency Injection gibt Ihnen diese Kontrolle, so dass Sie das Objekt unter Test mit Mocks / Stubs / etc zu isolieren. Dies ist, wie Sie Objekte in Isolation getestet werden.

  

Separate UI-Code von seinem Verhalten unter Verwendung von Model-View-Controller-oder Model-View-Presenter.

Einverstanden. Beachten Sie, dass auch der Moderator / Controller DI / IoC getestet werden können, unter Verwendung, indem sie ihm eine gekürzte / verspottete Ansicht und Modell übergeben. Schauen Sie sich Presenter Erste TDD für mehr dazu.

  

Schreiben Sie nicht statische Methoden oder Klassen.

Nicht sicher, ob ich mit diesem zustimmen. Es ist möglich, Unit-Test eine statische Methode / Klasse ohne Mocks zu verwenden. Also, vielleicht ist dies eine jener Rhino Mock spezifischer Regeln, die Sie erwähnen.

  

Programm off-Schnittstellen, keine Klassen.

Ich bin damit einverstanden, aber für einen etwas anderen Grund. Schnittstellen bietet ein hohes Maß an Flexibilität an den Softwareentwickler - darüber hinaus nur für verschiedenes Mock-Objekt-Frameworks unterstützen. Zum Beispiel ist es nicht möglich, DI richtig ohne Schnittstellen zu unterstützen.

  

Isolieren Sie externe Abhängigkeiten.

Einverstanden. Ausblenden externe Abhängigkeiten hinter Ihren eigenen Fassade oder Adapter (je nach Bedarf) mit einer Schnittstelle. Dies ermöglicht Ihnen, Ihre Software von der externen Abhängigkeit zu isolieren, ist es eine Web-Service, eine Warteschlange, eine Datenbank oder etwas anderes. Dies ist insbesondere wichtig, wenn Ihr Team hat keine Kontrolle über die Abhängigkeit (auch bekannt als extern).

  

Mark als virtuelle Methoden beabsichtigen Sie zu verspotten.

Das ist eine Beschränkung von Rhino Mocks. In einer Umgebung, die Hand codierte Stubs über einen Mockobjekt Rahmen vorzieht, das wäre nicht notwendig sein.

Und ein paar neue Punkte zu beachten:

Verwenden Sie creational Design Patterns. Das mit DI unterstützen wird, aber es ermöglicht Ihnen auch, dass Code zu isolieren und unabhängig von anderen Logik zu testen.

schreiben Tests mit Bill Wake Anordnen / Act / behaupten Technik . Diese Technik macht es sehr klar, welche Konfiguration notwendig ist, was tatsächlich getestet wird, und was erwartet wird.

Haben Sie keine Angst, Ihre eigenen Mocks / Stubs zu rollen. Oft werden Sie feststellen, dass Mockobjekt Frameworks Ihre Tests unglaublich schwer macht, zu lesen. Durch Ihre eigenen Rollen, werden Sie die vollständige Kontrolle über Ihre Mocks / Stubs haben, und Sie werden in der Lage sein, Ihre Tests lesbar zu halten. (Siehe zurück zum vorherigen Punkt).

Vermeiden Sie die Versuchung Duplizierung aus Ihren Unit-Tests in abstrakte Basisklassen oder Setup / Teardown Methoden Refactoring. Doing verbirgt so Konfiguration / clean-up-Code aus dem Entwickler versuchen, das Gerät zu testen grok . In diesem Fall ist die Klarheit der einzelnen Tests wichtiger als Vervielfältigung Refactoring aus.

Continuous Integration implementieren. Check-in Ihren Code auf jeder "grünen Balken." Erstellen Sie Ihre Software und führen Sie Ihre vollständige Suite von Unit-Tests auf jedem Check-in. (Sicher, dies ist keine Codierung der Praxis per se; aber es ist ein unglaubliches Werkzeug für Ihre Software sauber und voll integriert zu halten.)

Andere Tipps

Wenn Sie mit .NET 3.5 arbeiten, können Sie in die Moq spöttische Bibliothek -. es verwendet Ausdruck Bäume und Lambda-Ausdrücke nicht-intuitive Rekord-Antwort Idiom der meisten anderen spöttischen Bibliotheken zu entfernen

Schauen Sie sich diese quickstart zu sehen, wie viel intuitiver Ihre Testfälle werden, hier ist ein einfaches Beispiel:

// ShouldExpectMethodCallWithVariable
int value = 5;
var mock = new Mock<IFoo>();

mock.Expect(x => x.Duplicate(value)).Returns(() => value * 2);

Assert.AreEqual(value * 2, mock.Object.Duplicate(value));

Kennen Sie den Unterschied zwischen Fakes, Mocks und Stubs und wenn jeder verwenden.

Vermeiden Sie über Wechselwirkungen Angabe mit Mocks. Dies macht Tests spröde .

Dies ist ein sehr hilfreicher Beitrag!

Ich mag hinzufügen, dass es immer wichtig ist, den Kontext und System Under Test (SUT) zu verstehen. TDD Prinzipien Nach dem Schreiben ist viel einfacher, wenn Sie das Schreiben neuen Code in einer Umgebung, in bestehendem Code, um die gleichen Prinzipien folgt. Aber wenn man in einer nicht TDD Legacy-Umgebung neuen Code schreiben Sie feststellen, dass Ihre TDD Bemühungen schnell weit über Ihre Einschätzungen und Erwartungen des Ballon können.

Für einige von euch, die in einer ganz akademischen Welt leben, Zeitrahmen und die Lieferung kann nicht wichtig sein, aber in einer Umgebung, in Software Geld, effektive Nutzung Ihrer TDD Anstrengung, ist von entscheidender Bedeutung.

TDD ist in hohem Maße unterliegen dem Gesetz der abnehmenden Grenz Return . Kurz gesagt, sind Ihre Bemühungen um TDD immer wertvoller, bis Sie einen Punkt maximaler Rendite getroffen, wonach investierte späteren Zeitpunkt in TDD immer weniger Wert hat.

Ich neige dazu, zu glauben, dass primärer Wert des TDD in Grenze (Blackbox) sowie in gelegentlichem White-Box-Test von unternehmenskritischen Bereichen des Systems.

Der wahre Grund für die Programmierung gegen Schnittstellen ist nicht das Leben leichter zu machen für Rhino, aber die Beziehungen zwischen Objekten im Code zu klären. Eine Schnittstelle soll einen Dienst definieren, die ein Objekt von seiner Umgebung benötigt. A-Klasse stellt eine besondere Implementierung dieses Dienstes. Lesen Sie Rebecca Wirfs-Brock "Object Design" Buch über die Rollen, Verantwortlichkeiten und Mitarbeiter.

Gute Liste. Eines der Dinge, die Sie vielleicht aufbauen wollen - und ich kann Ihnen viel Rat nicht geben, da ich gerade fange an, darüber nachzudenken mich - ist, wenn eine Klasse in einer anderen Bibliothek, Namespace, verschachtelte Namespaces sein sollte. Man könnte sogar eine Liste von Bibliotheken, um herauszufinden, will und Namespaces vorher und Mandat, dass das Team zu treffen hat und zu entscheiden, zwei fusionieren / einen neuen hinzufügen.

Oh, dachte nur an etwas, das ich tun, dass Sie auch möchten vielleicht. Ich habe im Allgemeinen eine Unit-Tests Bibliothek mit einer Prüfvorrichtung pro Klasse Politik, in denen jeder Test in einen entsprechenden Namensraum geht. Ich neige dazu, auch eine andere Bibliothek von Tests (Integrationstests?) Zu haben, die in einem BDD Stil . Dies ermöglicht es mir, Tests zu schreiben, um spec, was die Methode sollte auch das tun, was die Anwendung Gesamt tun sollte.

Hier ist eine andere, die ich gedacht, dass ich tun.

Wenn Sie planen Tests von der Unit-Test-Gui laufen im Gegensatz zu von TestDriven.Net oder NAnt dann finde ich habe es einfacher, den Unit-Tests Projekttyp einstellt Anwendung auf der Konsole statt Bibliothek. Auf diese Weise können Sie Tests manuell und Schritt durch sie im Debug-Modus laufen zu lassen (was die zuvor erwähnte TestDriven.Net tatsächlich für Sie tun).

Auch Ich mag immer offen ein Spielplatz-Projekt haben, um Bits von Code und Ideen zu testen Ich bin nicht vertraut mit. Dies sollte nicht in der Quellcodeverwaltung überprüft werden. Noch besser ist, es sollte nur auf der Entwickler-Maschine in einem separaten Quellcodeverwaltungsrepository sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top