Funktioniert TDD wirklich für komplexe Projekte?

53

Ich stelle diese Frage zu Problemen, die ich bei TDD-Projekten hatte. Beim Erstellen von Komponententests sind mir die folgenden Herausforderungen aufgefallen.

  • Generieren und Pflegen von Scheindaten

Es ist schwierig und unrealistisch, große Scheindaten zu verwalten. Es ist noch schwieriger, wenn sich die Datenbankstruktur ändert.

  • GUI testen

Selbst mit MVVM und der Möglichkeit, die GUI zu testen, ist viel Code erforderlich, um das GUI-Szenario zu reproduzieren.

  • Testen Sie das Geschäft

Ich habe die Erfahrung gemacht, dass TDD gut funktioniert, wenn Sie es auf einfache Geschäftslogik beschränken. Komplexe Geschäftslogik ist jedoch schwer zu testen, da die Anzahl der Testkombinationen (Testbereich) sehr groß ist.

  • Widerspruch in den Anforderungen

In der Realität ist es schwierig, alle Anforderungen zu analysieren und zu entwerfen. Oft führen Anforderungen an eine Notiz zu Widersprüchen, da das Projekt komplex ist. Der Widerspruch wird erst spät in der Umsetzungsphase festgestellt. TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind. In solchen Fällen ist zu erwarten, dass bei der Erstellung von Tests widersprüchliche Anforderungen erfasst werden. Das Problem ist jedoch, dass dies in komplexen Szenarien nicht der Fall ist.

Ich habe die Frage gelesen: Warum funktioniert TDD?

Funktioniert TDD wirklich für komplexe Unternehmensprojekte oder ist es praktisch auf den Projekttyp beschränkt?

Amir Rezaei
quelle
+1 Ich hatte die gleiche Frage nach dem Lesen dieser Frage - ich benutze sie in begrenztem Umfang mit dem gleichen Problem mit Scheindaten.
Michael K
20
"TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind", wobei "Anforderungen" "Ich muss wissen, wie diese einzelne Methode funktionieren muss". Und wenn Sie nicht wissen, wie die Methode funktionieren soll, wie sollen Sie sie implementieren?
Frank Shearar
@FrankShearar: Sie wissen, wie die Methode bei erwarteten Eingaben funktionieren soll. Angenommen, strcmp muss 2 Zeiger annehmen, von denen keiner nullptr ist und beide gültig sind. Sie wissen nicht, was passiert, wenn Sie einen falschen Zeiger eingeben. Vielleicht können Sie auf einigen Architekturen AV einfangen und etwas Vernünftiges tun, aber Sie können sich nicht vorstellen, dass ein solches Szenario möglich ist, sodass Ihre Tests es nicht abdecken.
Coder
7
Ich würde sagen, TDD ist das einzige, was für große Projekte funktioniert! Je größer das Projekt, desto komplexer die Interaktionen und desto mehr Anforderungen ändern sich zufällig - nur TDD kann mithalten
Martin Beckett
2
Tatsächlich ist das Tolle an TDD in Bezug auf Anforderungsänderungen, dass Sie, wenn sich die Anforderungen ändern, einfach einen neuen Test für diese Anforderung schreiben und sicherstellen können, dass der Rest des Projekts nicht beeinträchtigt wird. Wenn Sie noch keinen Test geschrieben haben, müssen Sie auch Tests schreiben, um sicherzustellen, dass Ihre Änderung nichts anderes beeinträchtigt. Auch ich liebe es für Bugfixes. Auch wenn Sie nicht alles mit TDD entwickelt haben, verwenden Sie es zur Fehlerbehebung: Schreiben Sie einen Test, der den Fehler reproduziert, beheben Sie den Fehler und führen Sie den Test erneut aus.
Jordan Reiter

Antworten:

53

Es ist schwierig und unrealistisch, große Scheindaten zu verwalten. Es ist noch schwieriger, wenn sich die Datenbankstruktur ändert.

Falsch.

Unit-Tests erfordern keine "großen" Scheindaten. Es sind genügend Scheindaten erforderlich, um die Szenarien zu testen, und nicht mehr.

Außerdem bitten die wirklich faulen Programmierer die Fachexperten, einfache Tabellenkalkulationen der verschiedenen Testfälle zu erstellen. Nur eine einfache Tabelle.

Dann schreibt der faule Programmierer ein einfaches Skript, um die Tabellenzeilen in Komponententestfälle umzuwandeln. Es ist wirklich ziemlich einfach.

Wenn sich das Produkt weiterentwickelt, werden die Arbeitsblätter der Testfälle aktualisiert und neue Komponententests generiert. Mach es die ganze Zeit. Es funktioniert wirklich.

Selbst mit MVVM und der Möglichkeit, die GUI zu testen, ist viel Code erforderlich, um das GUI-Szenario zu reproduzieren.

Was? "Reproduzieren"?

Der Zweck von TDD ist es, Dinge für die Testbarkeit zu entwerfen (Test Drive Development). Wenn die GUI so komplex ist, muss sie umgestaltet werden, um einfacher und testbarer zu sein. Einfacher bedeutet auch schneller, wartbarer und flexibler. Aber meistens bedeutet einfacher prüfbarer.

Ich habe die Erfahrung gemacht, dass TDD gut funktioniert, wenn Sie es auf einfache Geschäftslogik beschränken. Komplexe Geschäftslogik ist jedoch schwer zu testen, da die Anzahl der Testkombinationen (Testbereich) sehr groß ist.

Das kann wahr sein.

Es ist jedoch sehr hilfreich, die Fachexperten aufzufordern, die wichtigsten Testfälle in einer einfachen Form (wie einer Tabelle) bereitzustellen.

Die Tabellenkalkulationen können ziemlich groß werden. Aber das ist in Ordnung, da ich ein einfaches Python-Skript verwendet habe, um die Arbeitsblätter in Testfälle umzuwandeln.

Und. Ich musste einige Testfälle manuell schreiben, da die Tabellen unvollständig waren.

Jedoch. Als die Benutzer "Bugs" meldeten, fragte ich einfach, welcher Testfall in der Tabelle falsch war.

In diesem Moment korrigierten die Fachexperten entweder die Tabelle oder fügten Beispiele hinzu, um zu erklären, was passieren sollte. Die Fehlerberichte können - in vielen Fällen - eindeutig als Testfallproblem definiert werden. Meiner Erfahrung nach macht die Definition des Fehlers als fehlerhafter Testfall die Diskussion sehr viel einfacher.

Anstatt Experten zuzuhören, die versuchen, einen überkomplexen Geschäftsprozess zu erklären, müssen die Experten konkrete Beispiele für den Prozess erstellen.

TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind. In solchen Fällen ist zu erwarten, dass bei der Erstellung von Tests widersprüchliche Anforderungen erfasst werden. Das Problem ist jedoch, dass dies in einem komplexen Szenario nicht der Fall ist.

Wenn Sie TDD nicht verwenden, müssen die Anforderungen unbedingt zu 100% stimmen. Einige behaupten, dass TDD unvollständige und sich ändernde Anforderungen tolerieren kann, während ein Ansatz ohne TDD nicht mit unvollständigen Anforderungen funktionieren kann.

Wenn Sie TDD nicht verwenden, wird der Widerspruch erst spät in der Implementierungsphase festgestellt.

Wenn Sie TDD verwenden, wird der Widerspruch früher festgestellt, wenn der Code einige Tests besteht und andere Tests nicht bestehen. In der Tat liefert TDD den Beweis für einen Widerspruch zu einem früheren Zeitpunkt im Prozess, lange vor der Implementierung (und Argumente während der Benutzerakzeptanztests).

Sie haben Code, der einige Tests besteht und andere nicht besteht. Sie betrachten nur diese Tests und Sie finden den Widerspruch. In der Praxis funktioniert das sehr, sehr gut, denn jetzt müssen sich die Benutzer über den Widerspruch streiten und konsistente, konkrete Beispiele für das gewünschte Verhalten liefern.

S.Lott
quelle
4
@ S.Lott Da das OP in Bezug auf MVVM höchstwahrscheinlich über WPF / SL spricht, sind die Kommentare zu den GUI-Tests etwas verfremdet. Selbst bei Entkopplung und einem strengen MVVM-Ansatz ist das Testen von View per Definition immer noch umständlich. Dies ist mit jeder Benutzeroberfläche möglich. Das Testen der Ansicht ist bekanntermaßen zeitaufwändig, umständlich und mit einem niedrigen ROI verbunden. Dies ist der Punkt, an dem das Argument in Bezug auf MVVM-Oberflächen, dass das Testen des M / VM und das Nichtbeachten des V der beste Ansatz ist, jedoch das Testen von Komponenten in der Ansicht, wie z Komplex.
Aaron McIver
3
@ S.lott Kommt auf den Umfang an. TDD bietet keinen wesentlichen Wert in Bezug auf das Testen einer Ansicht. TDD bietet jedoch erhebliche Vorteile beim Testen von Model und ViewModel. Wenn Ihr Bereich das ViewModel und View war, würde der Wert von TDD basierend auf Ihrem Bereich sehr unterschiedlich sein, wenn Ihr Bereich das Modell und die erforderlichen Services wäre. Verstehen Sie mich nicht falsch, ich glaube, dass TDD für komplexe Projekte einen erheblichen Wert hat. Der Wert variiert je nach Umfang.
Aaron McIver
5
@ Robert Harvey: Es kann nicht meine Erfindung sein. Ich bin zu faul, um etwas zu erfinden.
S.Lott
4
@Amir Rezaei: Es tut mir leid, dass Ihre minimalen Unit-Test-Daten komplex sind. Das hat nichts mit TDD zu tun. Ihre Bewerbung ist komplex. Du musst es noch testen, oder? Sie müssen noch Testdaten vorlegen? Wenn Sie TDD nicht folgen, wie erstellen Sie dann eine testbare Anwendung? Glück? Hoffnung? Ja. Es ist komplex. Nichts beseitigt die Komplexität. TDD versichert, dass Sie diese Komplexität tatsächlich testen werden.
S.Lott
4
@Amir Rezaei: "Wir gestalten für die Realität". Wirst du Tests schreiben? Wenn ja, dann Design für Testbarkeit. Wenn Sie keine Tests schreiben, woher wissen Sie dann, dass etwas funktioniert?
S.Lott
28

Ja

Meine erste Erfahrung mit TDD bestand darin, an den Middleware-Komponenten für ein Linux-basiertes Mobiltelefon zu arbeiten. Das ergab schließlich Millionen von Quellcodezeilen, die wiederum 9 Gigabyte Quellcode für verschiedene Open-Source-Komponenten erforderten.

Von allen Autoren von Komponenten wurde erwartet, dass sie sowohl eine API als auch eine Reihe von Komponententests vorschlagen und diese von einem Peer-Committee überprüfen lassen. Niemand erwartete beim Testen Perfektion, aber für alle öffentlich zugänglichen Funktionen musste mindestens ein Test durchgeführt werden, und sobald eine Komponente der Quellcodeverwaltung unterzogen wurde, mussten alle Komponententests immer bestanden werden (auch wenn dies der Fall war, weil die Komponente fälschlicherweise meldete) es hat gut funktioniert).

Zumindest teilweise auf TDD zurückzuführen und darauf, dass alle Komponententests immer bestanden wurden, erschien die Version 1.0 früh, unter dem Budget und mit erstaunlicher Stabilität.

Nach der Veröffentlichung von 1.0 forderten die Unternehmen auf, die Durchführung von TDD zu beenden und die Anforderung, dass Komponententests bestanden werden, zu streichen, da sie den Umfang aufgrund von Kundenanforderungen schnell ändern wollten. Es war erstaunlich, wie schnell die Qualität auf die Toilette ging, und dann folgte der Zeitplan.

Bob Murphy
quelle
8
removed the requirement that unit tests pass. It was astonishing how quickly quality went down the toilet, and then the schedule followed it.- Es ist, als würde man seinem F1-Fahrer sagen, dass er keine Boxenstopps einlegen darf, weil es zu lange dauert ... Idiotisch.
Jess Telford
1
Dies veranschaulicht, was ich immer wieder sage: Der einzige Weg, schnell zu gehen, ist, gut zu gehen !
TheCatWhisperer
18

Ich würde sagen, je komplexer das Projekt ist, desto mehr profitieren Sie von TDD. Die Hauptvorteile sind die Nebenwirkungen, durch die TDD Sie zwingt, den Code in viel kleineren, viel unabhängigeren Blöcken zu schreiben. Hauptvorteile sind:

a) Sie erhalten eine sehr viel frühere Validierung Ihres Designs, da Ihre Rückkopplungsschleife aufgrund von Tests von Anfang an viel enger ist.

b) Sie können Kleinigkeiten austauschen und sehen, wie das System reagiert, da Sie die ganze Zeit über eine Testabdeckung erstellt haben.

c) Der fertige Code wird dadurch viel besser.

Wyatt Barnett
quelle
1
Ich sehe und kenne die Vorteile von TDD. Ich diskutiere jedoch darüber, wie realistisch und wie viel Ressourcen und Geld erforderlich sind, um TDD in solchen Projekten durchzuführen.
Amir Rezaei
Da muss ich dir zustimmen In komplexen Projekten gibt es (meiner Meinung nach) keinen anderen Weg, um sicherzustellen, dass alles funktioniert als die Tests ... Wenn viele Programmierer auf Ihrer Codebasis arbeiten, können Sie nicht sicher sein, dass niemand Ihre Arbeit geändert hat. Wenn der Test weiterhin besteht - kein Problem. Wenn nicht, wissen Sie, wo Sie suchen müssen.
31.01.13
10

Funktioniert TDD wirklich für komplexe Projekte?
Ja. Nicht jedes Projekt, so wurde mir gesagt, funktioniert gut mit TDD, aber die meisten Geschäftsanwendungen sind in Ordnung, und ich wette, diejenigen, die nicht gut funktionieren, wenn sie auf reine TDD-Weise geschrieben sind, könnten ohne größere Probleme auf ATDD-Weise geschrieben werden.

Generieren und Verwalten von Scheindaten
Halten Sie Ihre Daten klein und haben Sie nur das, was Sie benötigen. Dies ist anscheinend kein beängstigendes Problem. Versteh mich nicht falsch, es ist ein Schmerz. Aber es lohnt sich.

Testen der Benutzeroberfläche
Testen Sie die MVVM und stellen Sie sicher, dass sie ohne die Ansicht getestet werden kann. Ich fand das nicht schwieriger als das Testen eines anderen Teils der Geschäftslogik. Testen Sie die Ansicht in Code, den ich nicht tue. An dieser Stelle testen Sie jedoch nur die Bindungslogik, von der man hofft, dass sie schnell erkannt wird, wenn Sie einen schnellen manuellen Test durchführen.

Testen des Geschäfts
Kein Problem gefunden. Viele kleine Tests. Wie ich oben sagte, sind einige Fälle (Sudoku-Puzzle-Löser scheinen sehr beliebt zu sein) anscheinend schwierig, TDD zu machen.

TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind
. Woher hast du diese Idee? Alle agilen Praktiken akzeptieren, dass sich die Anforderungen ändern. Sie müssen wissen, was Sie tun, bevor Sie es tun, aber das ist nicht dasselbe, als wenn die Anforderungen 100% betragen müssen. TDD ist eine gängige Praxis in Scrum, bei der die Anforderungen (User Stories) per definitionem nicht zu 100% vollständig sind.

mlk
quelle
Wenn Sie keine genauen Anforderungen haben, wie fangen Sie überhaupt mit Unit-Tests an? Springen Sie während eines Sprints zwischen Implementierung und Design hin und her?
Amir Rezaei
Eine "Einheit" ist kleiner als eine Anforderung, und ja, dies kann im Allgemeinen durchgeführt werden, ohne dass die gesamte Benutzerkontensteuerung gebunden ist.
mlk
Wir testen jede Einheit und auch die Einheitentestkombination von Einheiten, das ist die Voraussetzung.
Amir Rezaei
9

Zunächst einmal glaube ich, dass es bei Ihrem Problem mehr um Unit-Tests im Allgemeinen als um TDD geht, da ich in Ihren Aussagen nichts wirklich TDD-spezifisches (Test-First + Rot-Grün-Refactor-Zyklus) sehe.

Es ist schwierig und unrealistisch, große Scheindaten zu verwalten.

Was meinen Sie mit Scheindaten? Ein Mock soll genau genommen kaum Daten enthalten, dh keine anderen Felder als das eine oder andere, die im Test benötigt werden, und keine anderen Abhängigkeiten als das zu testende System. Das Einrichten einer Scheinerwartung oder eines Rückgabewerts kann in einer Zeile erfolgen, also nichts Schreckliches.

Es ist noch schwieriger, wenn sich die Datenbankstruktur ändert.

Wenn Sie meinen, dass die Datenbank Änderungen erfährt, ohne dass die entsprechenden Änderungen am Objektmodell vorgenommen wurden, sind genau die Unit-Tests hilfreich, um Sie davor zu warnen. Andernfalls müssen Änderungen am Modell offensichtlich in den Komponententests berücksichtigt werden, aber bei Kompilierungsangaben ist dies eine einfache Sache.

Selbst mit MVVM und der Möglichkeit, die GUI zu testen, ist viel Code erforderlich, um das GUI-Szenario zu reproduzieren.

Sie haben Recht, das Testen der GUI (View) ist nicht einfach, und viele Leute tun es auch ohne (außerdem gehört das Testen der GUI nicht zu TDD). Im Gegensatz dazu ist es einer der Hauptgründe für das Testen von Mustern wie MVC oder MVVM, wenn Sie Ihren Controller / Presenter / ViewModel / eine beliebige Zwischenschicht testen.

Ich habe die Erfahrung gemacht, dass TDD gut funktioniert, wenn Sie es auf einfache Geschäftslogik beschränken. Komplexe Geschäftslogik ist jedoch schwer zu testen, da die Anzahl der Testkombinationen (Testbereich) sehr groß ist.

Wenn Ihre Geschäftslogik komplex ist, ist es normal, dass Ihre Komponententests schwer zu entwerfen sind. Es liegt an Ihnen, sie so atomar wie möglich zu gestalten und jeweils nur eine Verantwortung des zu prüfenden Objekts zu prüfen. Unit-Tests werden in einer komplexen Umgebung umso mehr benötigt, als sie ein Sicherheitsnetz bieten, das garantiert, dass Sie bei Änderungen am Code nicht gegen Geschäftsregeln oder -anforderungen verstoßen.

TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind.

Absolut nicht. Erfolgreiche Software setzt voraus, dass die Anforderungen zu 100% korrekt sind. Wenn die Vision fehlerhaft ist, werden auch Ihr Code und Ihre Software Komponententests sein oder nicht ... Und hier leuchten Komponententests: Mit ausreichend expliziten Testtiteln werden Ihre Entwurfsentscheidungen und die Interpretation der Anforderungen transparent, was es einfacher macht, darauf hinzuweisen Finden Sie heraus, was beim nächsten Mal geändert werden muss, wenn Ihr Kunde sagt: "Diese Geschäftsregel ist nicht so, wie ich es gerne hätte."

guillaume31
quelle
6

Ich muss lachen, wenn ich jemanden beschweren höre, dass er TDD nicht zum Testen seiner Anwendung verwenden kann, weil seine Anwendung so kompliziert ist. Was ist die Alternative? Haben Sie Testaffen, die auf einem Hektar großen Tastaturgebiet herumtollen? Lassen Sie die Benutzer die Tester sein? Was sonst? Natürlich ist es schwierig und komplex. Denken Sie, dass Intel die Chips erst testet, wenn sie ausgeliefert werden? Wie "head-in-the-sand" ist das?

SnoopDougieDoug
quelle
5
Hochqualifizierte, professionelle Mitarbeiter, die einfachen und effektiven Code schreiben. Und Tester verwenden. Dieser Ansatz hat sich bei vielen erfolgreichen Unternehmen bewährt.
Coder
Eine Alternative sind Regressionstests. Denken Sie beispielsweise an das Testen eines Webbrowsers. Angenommen, Sie sind Google und möchten eine neue Version von Chrome testen. Sie können jedes einzelne CSS-Element und jedes Attribut jedes HTML-Tags sowie alle grundlegenden Funktionen von JavaScript testen. Aber wie viele mögliche Kombinationen dieser Funktionen gibt es? Ich glaube nicht, dass irgendjemand das wissen kann. Sie führen alle Arten von Tests einzelner Funktionen in verschiedenen Kabelbäumen durch, aber letztendlich führen sie eine Regression gegen eine bekannte Bank von Websites durch. Das sind die Millionen Affen genau dort.
Dan Korn
Die realistische Alternative besteht darin, Software bereitzustellen, die nicht funktioniert. Dies kann unter den richtigen Umständen noch rentabel sein. Wählen Sie Ihr Lieblingsbeispiel.
Soru
4

Ich habe festgestellt, dass TDD (und Unit-Tests im Allgemeinen) aus einem ähnlichen Grund praktisch unmöglich sind: Komplexe, neuartige und / oder unscharfe Algorithmen. Das Problem, auf das ich bei den Forschungsprototypen, die ich schreibe, am häufigsten stoße, ist, dass ich keine Ahnung habe, was die richtige Antwort ist, außer meinen Code auszuführen. Es ist zu kompliziert, für alles andere als lächerlich triviale Fälle einigermaßen von Hand herauszufinden. Dies gilt insbesondere dann, wenn der Algorithmus Heuristiken, Approximationen oder Nichtdeterminismus umfasst. Ich versuche immer noch, die Funktionalität auf niedrigerer Ebene zu testen, von der dieser Code abhängt, und verwende Asserts stark zur Überprüfung der Integrität. Meine letzte Möglichkeit zum Testen besteht darin, zwei verschiedene Implementierungen zu schreiben, idealerweise in zwei verschiedenen Sprachen, wobei zwei verschiedene Bibliotheksgruppen verwendet werden, und die Ergebnisse zu vergleichen.

dsimcha
quelle
Ich habe dieses Problem gehabt. Sie benötigen einfache Fälle, die "von Hand" ausgearbeitet wurden, und einen ausreichend komplexen Fall, der von einem Domain-Experten ausgearbeitet und validiert wurde. Wenn das niemand kann, liegt ein Spezifikationsproblem vor. Wenn Sie eine algorithmische Akzeptanzfunktion codieren können, auch wenn sie nicht den richtigen Formzustandsraum verlässt, können Sie sie für statistische Tests verwenden (führen Sie den Test 10000 Mal durch und sehen Sie sich den Antwortakzeptanztrend an)
Tim Williscroft
"und ein hinreichend komplexer Fall, der von einem Domain-Experten ausgearbeitet und validiert wurde" - Ist es dann ein Unit-Test oder ein Regressionstest?
quant_dev
2
@Tim: Ich bin der Domain-Experte (in meiner Branche ist in der Regel eine Person sowohl der Domain-Experte als auch der Programmierer) und ich kann dieses Zeug nicht vernünftig von Hand ausarbeiten. Andererseits weiß ich fast immer ungefähr, wie die Antwort lauten sollte (beispielsweise sollte ein Algorithmus für maschinelles Lernen einigermaßen genaue Vorhersagen treffen, ein Algorithmus mit zufälligen Daten sollte keine "interessanten" Ergebnisse liefern), aber dies ist schwer zu automatisieren. Auch für Forschungsprototypen gibt es fast nie eine formale Spezifikation.
DSIMCHA
@quant_dev es ist ein Unit-Test. Es testet das Verhalten des Geräts an einem komplexeren Testdatensatz. Sie können Komponententests für Regressionstests verwenden. Sie sollten auch Regressionstests für auftretende Fehler schreiben, um deren Wiederholung zu verhindern. (Es gibt starke Beweise dafür, dass Bugs Cluster)
Tim Williscroft
@dsimcha: Ein statistischer Ansatz für den Komponententest kann also für Sie funktionieren, da Sie einen ungefähren Prädiktor erstellen können. Ich habe diesen Ansatz in einem Waffensystem verwendet, um das sich bewegende Ziel auszuwählen und zu debuggen. Es ist sehr schwierig, Antworten dafür von Hand zu finden, aber es ist relativ einfach, herauszufinden, ob der Prädiktor funktioniert (Sie feuern ein Projektil virtuell ab und sehen, wo es virtuell aufschlägt, schäumen, 100000-mal spülen und Sie erhalten nette Ergebnisse wie "Algorithmus") A funktioniert in 91% der Fälle, AlgorithmB funktioniert in 85% der
Fälle
4
> Does TDD really work for complex projects?

Aus meiner Erfahrung: Ja für Unittests (Test von Modulen / Features isoliert), da diese meist nicht die von Ihnen genannten Probleme haben: (Gui, Mvvm, Business-Modell). Ich hatte nie mehr als 3 Mocks / Stubs, um einen Unittest zu erfüllen (aber möglicherweise erfordert Ihre Domain mehr).

Ich bin mir jedoch nicht sicher, ob TDD die Probleme lösen könnte, die Sie bei der Integration oder den End-to-End-Tests mit BDD-ähnlichen Tests angesprochen haben .

Aber zumindest einige Probleme können reduziert werden .

> However complex business logic is hard to test since the number 
> of combinations of tests (test space) is very large.

Dies ist der Fall, wenn Sie eine vollständige Abdeckung auf der Ebene des Integrationstests oder des End-to-End-Tests durchführen möchten. Es könnte einfacher sein, die vollständige Berichterstattung auf einer unbeschreiblichen Ebene durchzuführen.

Beispiel: Überprüfen komplexer Benutzerberechtigungen

Das Testen der Funktion IsAllowedToEditCusterData()auf einer Integrationstestebene würde erfordern, dass verschiedene Objekte nach Informationen über Benutzer, Domäne, Kunde, Umgebung ... gefragt werden.

Diese Teile zu verspotten ist ziemlich schwierig. Dies gilt insbesondere dann, wenn IsAllowedToEditCusterData()diese unterschiedlichen Objekte bekannt sein müssen.

Auf einer Unittest-Ebene hätten Sie eine Funktion IsAllowedToEditCusterData(), die zum Beispiel 20 Parameter akzeptiert, die alles enthalten, was die Funktion wissen muss. Da IsAllowedToEditCusterData()muss man nicht wissen, welche Felder a user, a domain, a customer, .... das hat man einfach zu testen.

Als ich implementieren musste, hatte IsAllowedToEditCusterData()ich zwei Überladungen davon:

Eine Überladung, die nichts weiter tut, als diese 20 Parameter abzurufen und dann die Überladung mit den 20 Parametern aufzurufen, die die Entscheidungen treffen.

(Meine IsAllowedToEditCusterData()hatte nur 5 Parameter und ich brauchte 32 verschiedene Kombinationen, um es vollständig zu testen)

Beispiel

// method used by businesslogic
// difficuilt to test because you have to construct
// many dependant objects for the test
public boolean IsAllowedToEditCusterData() {
    Employee employee = getCurrentEmployee();
    Department employeeDepartment = employee.getDepartment();
    Customer customer = getCustomer();
    Shop shop = customer.getShop();

    // many more objects where the permittions depend on

    return IsAllowedToEditCusterData(
            employee.getAge(),
            employeeDepartment.getName(),
            shop.getName(),
            ...
        );
}

// method used by junittests
// much more easy to test because only primitives
// and no internal state is needed
public static boolean IsAllowedToEditCusterData(
        int employeeAge,
        String employeeDepartmentName,
        String shopName,
        ... ) 
{
    boolean isAllowed; 
    // logic goes here

    return isAllowed;
}
k3b
quelle
1
+1 Sehr gutes Beispiel „Überprüfung komplexer Benutzerberechtigungen“, das genau eines unserer Szenarien ist.
Amir Rezaei
3

Die traurige Antwort ist, dass bei großen komplexen Projekten nichts wirklich funktioniert!

TDD ist so gut wie nichts anderes und besser als die meisten anderen, aber TDD allein garantiert keinen Erfolg bei einem großen Projekt. Es wird jedoch Ihre Erfolgschancen erhöhen. Insbesondere in Kombination mit anderen Projektmanagementdisziplinen (Anforderungsüberprüfung, Anwendungsfälle, Anforderungsverfolgbarkeitsmatrix, Code-exemplarische Vorgehensweisen usw.).

James Anderson
quelle
1

Denken Sie daran, dass Unit-Tests erzwungene Spezifikationen sind . Dies ist besonders bei komplexen Projekten von Nutzen. Wenn Ihre alte Codebasis keine Tests zum Sichern hat, wird sich niemand trauen, etwas zu ändern, weil sie Angst haben, etwas zu beschädigen.

"Wtf. Warum gibt es diese Code-Verzweigung überhaupt? Weiß nicht, vielleicht braucht es jemand, lass es besser, als jemanden zu verärgern ..." Im Laufe der Zeit werden die komplexen Projekte zu einem Müllland.

Bei Tests kann jeder mit Zuversicht sagen: "Ich habe drastische Änderungen vorgenommen, aber alle Tests sind noch nicht abgeschlossen." Per Definition hat er nichts gebrochen. Dies führt zu agileren Projekten, die sich entwickeln können. Vielleicht ist einer der Gründe, warum wir immer noch Leute brauchen, um COBOL zu warten, dass das Testen seitdem nicht populär war: P

kizzx2
quelle
1

Ich habe gesehen, dass ein großes komplexes Projekt völlig fehlgeschlagen ist, als TDD exklusiv verwendet wurde, dh ohne zumindest in einem Debugger / einer IDE einzurichten. Die Scheindaten und / oder Tests erwiesen sich als unzureichend. Die tatsächlichen Daten des Beta-Clients waren vertraulich und konnten weder kopiert noch protokolliert werden. Das Entwicklerteam konnte also niemals die schwerwiegenden Fehler beheben, die auftraten, wenn auf reale Daten verwiesen wurde, und das gesamte Projekt wurde verschrottet, alle feuerten, das ganze Stück.

Die Möglichkeit, dieses Problem zu beheben, bestand darin, es in einem Debugger am Clientstandort zu starten, mit den realen Daten zu vergleichen, den Code mit Haltepunkten, Überwachungsvariablen, Überwachungsspeicher usw. zu durchlaufen. Wer glaubte, sein Code könne die schönsten Elfenbeintürme schmücken, der hatte in einem Zeitraum von fast einem Jahr noch nie eine App gestartet. Das hat mich umgehauen.

Balance ist also wie alles der Schlüssel. TDD mag gut sein, aber verlassen Sie sich nicht ausschließlich darauf.

SPA
quelle
1
TDD verhindert nicht Idiotie. TDD ist ein Teil der Agilität, aber ein weiteres wichtiges
Element
0

Ich denke schon, Test Driven Development funktioniert wirklich

2008 verfassten Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat und Laurie Williams einen Artikel mit dem Titel „Qualitätsverbesserung durch testgetriebene Entwicklung: Ergebnisse und Erfahrungen von vier Industrieteams“ (PDF-Link). Die Zusammenfassung:

Testgetriebene Entwicklung (TDD) ist eine Softwareentwicklungspraxis, die seit Jahrzehnten sporadisch angewendet wird. Bei dieser Vorgehensweise wechselt ein Softwareentwickler von Minute zu Minute zwischen dem Schreiben fehlgeschlagener Komponententests und dem Schreiben von Implementierungscode, um diese Tests zu bestehen. Testgetriebene Entwicklung hat sich in letzter Zeit als kritisches Kriterium für die Anwendung agiler Softwareentwicklungsmethoden herausgestellt. Es gibt jedoch nur wenige empirische Beweise, die den Nutzen dieser Praxis im industriellen Kontext belegen oder widerlegen. Fallstudien wurden mit drei Entwicklerteams bei Microsoft und einem bei IBM durchgeführt, die TDD übernommen haben. Die Ergebnisse der Fallstudien zeigen, dass die Fehlerdichte vor der Freigabe der vier Produkte im Vergleich zu ähnlichen Projekten, bei denen die TDD-Praxis nicht angewendet wurde, zwischen 40% und 90% abnahm. Subjektiv,

Im Jahr 2012 übernehmen die Ruby on Rails-Entwicklungspraktiken TDD. Ich persönlich verlasse mich auf Tools wie rspec zum Schreiben von Tests und Verspottungen, factory_girl zum Erstellen von Objekten, capybara für die Browserautomatisierung, simplecov für die Codeabdeckung und guard für die Automatisierung dieser Tests.

Aufgrund der Verwendung dieser Methodik und dieser Tools stimme ich eher subjektiv mit Nagappan et al. Überein.

Hiltmon
quelle
0

Wenn die Kombination aus Budget, Anforderungen und Teamfähigkeiten im Quadranten des Projektraums steht und heißt, "hoffentlich alle aufgeben, die hier eintreten", ist es per definitionem mit überwältigender Wahrscheinlichkeit wahrscheinlich, dass das Projekt scheitert.

Vielleicht sind die Anforderungen komplex und volatil, die Infrastruktur instabil, das Team jünger und mit hohem Umsatz, oder der Architekt ist ein Idiot.

In einem TDD-Projekt besteht das Symptom für diesen bevorstehenden Fehler darin, dass Tests nicht termingerecht geschrieben werden können. Sie versuchen, nur um herauszufinden, "das wird so lange dauern , und wir haben nur das ".

Andere Ansätze zeigen andere Symptome, wenn sie fehlschlagen. am häufigsten Lieferung eines Systems, das nicht funktioniert. Politik und Verträge werden entscheiden, ob dies vorzuziehen ist.

Soru
quelle
-1

TDDDas klingt im Vorfeld vielleicht schmerzhaft, ist aber auf lange Sicht Ihr bester Freund. Vertrauen Sie mir, TDDdass die Anwendung auf lange Sicht wirklich wartbar und sicher ist.

Rachel
quelle