it-swarm.dev

Funktioniert TDD wirklich für komplexe Projekte?

Ich stelle diese Frage zu Problemen, die ich bei TDD-Projekten hatte. Ich habe die folgenden Herausforderungen beim Erstellen von Komponententests festgestellt.

  • Generieren und Verwalten von Scheindaten

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

  • Testen der GUI

Selbst mit MVVM und der Fähigkeit, die GUI zu testen, ist viel Code erforderlich, um das GUI-Szenario zu reproduzieren.

  • Testen des Geschäfts

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

  • Widerspruch in den Anforderungen

In der Realität ist es schwierig, alle Anforderungen zu analysieren, die analysiert und entworfen werden. Oft führen Anforderungen an eine Note zu Widersprüchen, da das Projekt komplex ist. Der Widerspruch wird spät in der Implementierungsphase festgestellt. TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind. In solchen Fällen könnte man erwarten, dass widersprüchliche Anforderungen beim Erstellen von Tests erfasst werden. Das Problem ist jedoch, dass dies in komplexen Szenarien nicht der Fall ist.

Ich habe diese Frage gelesen: Warum funktioniert TDD?

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

53
Amir Rezaei

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 werden genügend Scheindaten benötigt, 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 Unit-Testfälle umzuwandeln. Es ist wirklich ziemlich einfach.

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

Selbst mit MVVM und der Fähigkeit, die GUI zu testen, ist viel Code erforderlich, um das GUI-Szenario zu reproduzieren.

Was? "Reproduzieren"?

Bei TDD geht es darum, Dinge für die Testbarkeit zu entwerfen (Test Drive Development). Wenn die GUI so komplex ist, muss sie neu gestaltet werden, um einfacher und testbarer zu sein. Einfacher bedeutet auch schneller, wartbarer und flexibler. Aber meistens einfacher bedeutet testbarer.

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

Das kann wahr sein.

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

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

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

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

In diesem Moment würden die Fachexperten entweder die Tabelle korrigieren oder Beispiele hinzufügen, um zu erklären, was passieren sollte. Die Fehlerberichte können - in vielen Fällen - eindeutig als Testfallproblem definiert werden. Nach meiner Erfahrung macht die Definition des Fehlers als fehlerhaften Testfall die Diskussion viel, viel einfacher.

Anstatt Experten zuzuhören, die versuchen, einen superkomplexen 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 könnte man erwarten, dass widersprüchliche Anforderungen beim Erstellen von Tests erfasst werden. Das Problem ist jedoch, dass dies in komplexen Szenarien nicht der Fall ist.

Wenn TDD nicht verwendet wird, müssen die Anforderungen zu 100% korrekt sein. Einige behaupten, dass TDD unvollständige und sich ändernde Anforderungen tolerieren kann, wenn ein Nicht-TDD-Ansatz nicht mit unvollständigen Anforderungen arbeiten kann.

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

Wenn Sie TDD verwenden, wird der Widerspruch gefunden früher, wenn der Code einige Tests besteht und andere Tests nicht besteht. In der Tat gibt Ihnen TDD Beweis eines Widerspruchs 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 sehen sich nur diese Tests an und finden den Widerspruch. In der Praxis funktioniert es sehr, sehr gut, denn jetzt müssen die Benutzer über den Widerspruch streiten und konsistente, konkrete Beispiele für das gewünschte Verhalten erstellen.

52
S.Lott

Ja

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

Von allen Komponentenautoren wurde erwartet, dass sie sowohl eine API als auch eine Reihe von Komponententests vorschlagen und diese von einem Peer-Komitee auf Design prüfen lassen. Niemand erwartete Perfektion beim Testen, aber alle öffentlich zugänglichen Funktionen mussten mindestens einen Test haben, 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 Bericht erstattete es hat gut funktioniert).

Kein Zweifel, zumindest teilweise aufgrund von TDD und der Beharrlichkeit, dass alle Unit-Tests immer bestanden werden, kam die Version 1.0 früh, unter Budget und mit erstaunlicher Stabilität.

Nach der Version 1.0 forderten Unternehmen uns auf, die Durchführung von TDD zu beenden, da die Unternehmen aufgrund von Kundenanforderungen den Umfang schnell ändern wollten, und beseitigten die Anforderung, dass Unit-Tests bestanden werden müssen. Es war erstaunlich, wie schnell die Qualität auf die Toilette ging, und dann folgte der Zeitplan.

28
Bob Murphy

Ich würde sagen, je komplexer das Projekt ist, desto mehr Nutzen bringt Ihnen TDD. Die Hauptvorteile sind Nebenwirkungen, wie TDD Sie dazu zwingt, den Code in viel kleineren, viel unabhängigeren Blöcken zu schreiben. Hauptvorteile sind:

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

b) Sie können Teile ändern und sehen, wie das System reagiert, da Sie die ganze Zeit über einen Quilt mit Testabdeckung erstellt haben.

c) Der fertige Code ist dadurch viel besser.

18
Wyatt Barnett

Funktioniert TDD wirklich für komplexe Projekte?
Ja. Nicht jedes Projekt 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 es klein und haben Sie nur das, was Sie brauchen, und dies ist anscheinend nicht das beängstigende Problem. Versteh mich nicht falsch, es ist ein Schmerz. Aber es lohnt sich.

GUI testen
Testen Sie die MVVM und stellen Sie sicher, dass sie ohne die Ansicht getestet werden kann. Ich fand das nicht schwieriger, als irgendein anderes Stück Geschäftslogik zu testen. Testen der Ansicht in Code, den ich nicht mache, alles, was Sie testen, ist jedoch an dieser Stelle eine verbindliche Logik, von der man hofft, dass sie schnell erkannt wird, wenn Sie einen schnellen manuellen Test durchführen.

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

TDD setzt voraus, dass die Anforderungen zu 100% korrekt sind
Nein, tut es nicht. 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, wo die Anforderungen (User Stories) per Definition nicht zu 100% vollständig sind.

10
mlk

Zunächst einmal glaube ich, dass es in 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-Refaktor-Zyklus) sehe.

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

Was meinst du mit Scheindaten? Ein Mock soll genau kaum Daten enthalten, dh keine anderen Felder als die ein oder zwei, 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 unterliegt, ohne dass die richtigen Änderungen am Objektmodell vorgenommen wurden, sind Unit-Tests genau hier, um Sie davor zu warnen. Andernfalls müssen Änderungen am Modell natürlich in den Komponententests berücksichtigt werden, aber mit Kompilierungsangaben ist dies eine einfache Sache.

Selbst mit MVVM und der Fähigkeit, die GUI zu testen, ist viel Code erforderlich, um das GUI-Szenario zu reproduzieren.

Sie haben Recht, das Testen der Benutzeroberfläche (Ansicht) ist nicht einfach, und viele Leute kommen ohne sie gut zurecht (außerdem ist das Testen der Benutzeroberfläche nicht Teil von TDD). Im Gegensatz dazu ist das Testen Ihres Controllers/Presenter/ViewModel/einer Zwischenschicht, die dringend empfohlen wird, einer der Hauptgründe für Muster wie MVC oder MVVM.

Ich habe die Erfahrung gemacht, dass TDD gut funktioniert, wenn Sie es auf einfache Geschäftslogik beschränken. Eine komplexe Geschäftslogik ist jedoch schwer zu testen, da die Anzahl der Testkombinationen (Testraum) 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, wobei jeder nur eine Verantwortung für das zu testende Objekt testet. Unit-Tests werden in einer komplexen Umgebung umso mehr benötigt, als sie ein Sicherheitsnetz bieten, das sicherstellt, 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;) Unit-Tests spiegeln nur Ihre Vision der aktuellen Anforderungen wider. Wenn die Vision fehlerhaft ist, sind es auch Ihr Code und Ihre Software, Unit-Tests oder nicht ... Und hier leuchten Unit-Tests: Mit ausreichend expliziten Testtiteln werden Ihre Entwurfsentscheidungen und die Interpretation der Anforderungen transparent, was das Zeigen erleichtert Ihr Finger auf das, was beim nächsten Mal geändert werden muss, wenn Ihr Kunde sagt: "Diese Geschäftsregel entspricht nicht ganz meinen Vorstellungen.".

9
guillaume31

Ich muss lachen, wenn ich jemanden beschweren höre, dass der Grund, warum er TDD nicht zum Testen seiner Anwendung verwenden kann, darin besteht, dass seine Anwendung so kompliziert ist. Was ist die Alternative? Haben Testaffen auf Hektar Tastaturen geschlagen? Lassen Sie die Benutzer die Tester sein? Was sonst? Natürlich ist es schwierig und komplex. Denken Sie, Intel testet seine Chips erst, wenn sie ausgeliefert werden? Wie "Kopf in den Sand" ist das?

6
SnoopDougieDoug
> 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 eine Unittest zu erfüllen (aber vielleicht erfordert Ihre Domain mehr).

Ich bin jedoch nicht sicher wenn TDD die von Ihnen erwähnten Probleme lösen könnte bei der Integration oder bei End-to-End-Tests mit BDD-Tests.

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 gilt, 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 Abdeckung auf einer unittest-Ebene durchzuführen.

Beispiel: Überprüfen komplexer Benutzerberechtigungen

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

Das Verspotten dieser Teile ist ziemlich schwierig. Dies gilt insbesondere dann, wenn IsAllowedToEditCusterData() diese verschiedenen Objekte kennen muss.

Auf einer Unittest-Ebene hätten Sie die Funktion IsAllowedToEditCusterData(), die zum Beispiel 20 Parameter verwendet, die alles enthalten, was die Funktion wissen muss. Da IsAllowedToEditCusterData() nicht wissen muss, welche Felder ein user, ein domain, ein customer, .... hat, ist dies leicht zu testen.

Als ich IsAllowedToEditCusterData() implementieren musste, hatte 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 Entscheidungsfindung übernehmen.

(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;
}
4
k3b

Ich habe festgestellt, dass TDD (und Unit-Tests im Allgemeinen) aus einem verwandten Grund praktisch unmöglich sind: Komplexe, neuartige und/oder Fuzzy-Algorithmen. Das Problem, auf das ich bei den von mir geschriebenen Forschungsprototypen am häufigsten stoße, ist, dass ich keine Ahnung habe, was die richtige Antwort ist, außer wenn ich meinen Code ausführe. Es ist zu kompliziert, um für alles andere als lächerlich triviale Fälle vernünftigerweise von Hand herauszufinden. Dies gilt insbesondere dann, wenn der Algorithmus Heuristiken, Approximationen oder Nichtdeterminismus umfasst. Ich versuche immer noch, die untergeordneten Funktionen zu testen, von denen dieser Code abhängt, und verwende Asserts stark als Sanity Checks. Meine letzte Testmethode besteht darin, zwei verschiedene Implementierungen zu schreiben, idealerweise in zwei verschiedenen Sprachen, wobei zwei verschiedene Sätze von Bibliotheken verwendet werden, und die Ergebnisse zu vergleichen.

4
dsimcha

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

TDD ist so gut wie alles andere und besser als die meisten anderen, aber TDD allein garantiert keinen Erfolg in einem großen Projekt. Dies erhöht jedoch Ihre Erfolgschancen. Insbesondere in Kombination mit anderen Projektmanagementdisziplinen (Anforderungsüberprüfung, Anwendungsfälle, Anforderungs-Traktabilitätsmatrix, Code-exemplarische Vorgehensweisen usw.).

3
James Anderson

Ich habe gesehen, dass ein großes komplexes Projekt vollständig fehlgeschlagen ist, wenn TDD ausschließlich verwendet wurde, d. H. Ohne zumindest einen Debugger/eine IDE einzurichten. Die Scheindaten und/oder Tests erwiesen sich als unzureichend. Die realen Daten der Beta-Clients waren vertraulich und konnten nicht kopiert oder protokolliert werden. Das Entwicklerteam konnte also niemals die schwerwiegenden Fehler beheben, die sich zeigten, 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 Client-Standort zu starten, anhand der realen Daten zu leben, den Code mit Haltepunkten, Überwachungsvariablen, Überwachungsspeicher usw. zu durchlaufen. Dieses Team Wer dachte, ihr Code sei geeignet, um die schönsten Elfenbeintürme zu schmücken, hatte über einen Zeitraum von fast einem Jahr noch nie seine 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.

1
SPA

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 er Angst hat, etwas zu beschädigen.

"Wtf. Warum ist dieser Code-Zweig überhaupt dort? Weiß nicht, vielleicht braucht ihn jemand, lass ihn besser dort, als jemanden zu verärgern ..." Mit der Zeit werden die komplexen Projekte zu einem Müllland.

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

1
kizzx2

Wenn die Kombination aus Budget, Anforderungen und Teamfähigkeiten im Quadranten des Projektraums liegt, in dem "Hoffnung aufgeben, alle, die hier eintreten", dann ist es per Definition mit überwältigender Wahrscheinlichkeit wahrscheinlich, dass das Projekt scheitern wird.

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

Bei einem TDD-Projekt besteht das Symptom für diesen bevorstehenden Fehler darin, dass Tests nicht rechtzeitig geschrieben werden können. Sie versuchen nur zu entdecken, dass 'das dies lange dauern wird, 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 bestimmen, ob dies vorzuziehen ist.

0
soru

Ich denke schon, siehe Test Driven Development funktioniert wirklich

Nachiappan Nagappan, E. Michael Maximilien, Thirumalesh Bhat und Laurie Williams schrieben 2008 einen Artikel mit dem Titel „Realisieren von Qualitätsverbesserungen 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. Mit dieser Vorgehensweise wechselt ein Softwareentwickler Minute für Minute zwischen dem Schreiben fehlgeschlagener Komponententests und dem Schreiben von Implementierungscode, um diese Tests zu bestehen. Die testgetriebene Entwicklung hat sich kürzlich als eine wichtige Methode für agile Softwareentwicklungsmethoden herausgestellt. Wenige empirische Belege stützen oder widerlegen jedoch die Nützlichkeit dieser Praxis im industriellen Kontext. Fallstudien wurden mit drei Entwicklungsteams bei Microsoft und einem bei IBM durchgeführt, die TDD eingeführt haben. Die Ergebnisse der Fallstudien zeigen, dass die Defektdichte der vier Produkte vor der Freisetzung im Vergleich zu ähnlichen Projekten, bei denen die TDD-Praxis nicht angewendet wurde, zwischen 40% und 90% abnahm. Subjektiv verzeichneten die Teams nach der Einführung von TDD eine Verlängerung der anfänglichen Entwicklungszeit um 15–35%.

Im Jahr 2012, Ruby on Rails Entwicklungspraktiken setzen TDD voraus. Ich persönlich verlasse mich auf Tools wie rspec zum Schreiben von Tests und Mocks, factory_girl zum Erstellen von Objekten, capybara für den Browser Automatisierung, simplecov für die Codeabdeckung und Schutz für die Automatisierung dieser Tests.

Aufgrund der Verwendung dieser Methodik und dieser Werkzeuge stimme ich Nagappan et al.

0
Hiltmon