Detaillierte Erläuterung des Unit-Tests

Überblick

  1. Was ist Unit-Test?
  2. Warum Unit-Tests durchführen?
  3. Einige Missverständnisse über Unit-Tests
  4. Was sind die gängigen Unit-Testing-Frameworks?
  5. Würdigung von Beispielen für jedes Framework
  6. Vergleich verschiedener Frameworks
  7. So führen Sie Unit-Tests durch
  8. Problemdenken

1. Was ist Unit-Test?

Wikipedia beschreibt es so: In der Computerprogrammierung ist Unit-Test, auch Modultest genannt, ein Test zur Korrektheitsprüfung von Programmmodulen. Eine Programmeinheit ist die kleinste testbare Komponente einer Anwendung. Bei der prozeduralen Programmierung ist eine Einheit ein einzelnes Programm, eine einzelne Funktion, ein einzelner Prozess usw.; bei der objektorientierten Programmierung ist die kleinste Einheit eine Methode, einschließlich Methoden in Basisklassen, abstrakten Klassen oder abgeleiteten Klassen.

Der Unterschied zwischen Unit-Tests und Integrationstests

Die für Unit-Tests und Integrationstests verwendeten Test-Frameworks und -Tools sind größtenteils identisch.

Als erstes muss man sich darauf einigen, dass es sich um automatisierte Tests handelt, ganz gleich, ob es sich um Komponententests oder Integrationstests handelt. Zur besseren Unterscheidung können wir es so verstehen: Es befindet sich im selben Code-Warehouse wie der Produktionscode und der Unit-Test-Code, wird von den Entwicklungsstudenten selbst geschrieben und hat reale Auswirkungen auf die externe Umgebung (Datenbank, Datei). System, externes System, Nachrichtenwarteschlange usw.) Die aufgerufenen Tests sind Integrationstests.

In der folgenden Tabelle werden auch die Unterschiede zwischen Unit-Tests, Integrationstests und Tests auf Systemebene (einschließlich End-to-End-Tests, Link-Tests, automatisierter Regressionstests, UI-Tests usw.) aus verschiedenen Perspektiven verglichen.

Gerätetest Integrationstests Tests auf Systemebene
Schriftsteller entwickeln entwickeln Entwicklung/Test
Ort des Schreibens Im Produktionscode-Warehouse Im Produktionscode-Warehouse Innerhalb des Produktionscode-Lagers/Außerhalb des Produktionscode-Lagers
Schreibzeit Vor der Code-Veröffentlichung Vor der Code-Veröffentlichung Vor der Code-Veröffentlichung/Nach der Code-Veröffentlichung
Schreibkosten Niedrig Mitte hoch
Schwierigkeiten beim Schreiben Niedrig Mitte hoch
Feedback-Geschwindigkeit Extrem schnell, Sekunden Langsamer, Minutenpegel Langsam, Tagesniveau
Abdeckungsbereich Codezeilenabdeckung 60–80 % Zweigstellenabdeckung 40–60 % Abdeckung der Funktionsebene Link zur Kernsicherung
Umweltabhängigkeit Codeebene, unabhängig von der Umgebung Verlassen Sie sich auf die tägliche oder lokale Umgebung Hängt von der Staging- oder Produktionsumgebung ab
Externe Abhängigkeitssimulation Alle Simulationen Teilsimulation Keine Simulation, nutzen Sie vollständig die reale Umgebung

Zweitens: Warum brauchen wir Unit-Tests?

Nutzen:

  1. Verbessern Sie die Systemstabilität und erleichtern Sie die Iteration.

  2. Förderlich für ein tiefgreifendes Verständnis von Technologie und Wirtschaft.

  3. Die Kosten für einen einzelnen Test sind gering und die Geschwindigkeit ist hoch.

  4. Ein einzelner Test ist das beste, automatisierte und ausführbare Dokument.

  5. Das durch einzelne Tests getriebene Design verbessert die Einfachheit und Standardisierung des Codes und sorgt für sicheres Refactoring. Nachdem der Code geändert wurde, kann der einzelne Test immer noch bestanden werden, was das Vertrauen der Entwickler stärken kann.

  6. Schnelles Feedback, schnellere Erkennung von Problemen, schnellere und genauere Lokalisierung von Fehlern als bei Integrationstests und Reduzierung der Reparaturkosten.

    Geringe Entwicklungskosten:

    1,

    Die intuitivste Idee:

    2,

    Diese Idee ist in der Tat die intuitivste. Dies bezieht sich jedoch nur auf die erste Ebene. Wenn wir  alle Schritte des Entwicklungsprozesses hinzufügen  , werden wir feststellen, dass es so ist:

    Hinter dem Entwicklungsprozess können in fast jedem Prozess Fehler auftreten. Je mehr Fehler später im Prozess auftreten, desto mehr Zeit und Geschäft muss der Programmierer investieren als in der Entwicklungsphase, und auch die Risiken, die er eingeht, sind am höchsten.

Das Bild unten verdeutlicht auch zwei Probleme: Erstens werden 85 % der Fehler in der Code-Designphase erzeugt; zweitens sind die Kosten umso höher, je später die Phase entdeckt wird, in der Fehler entdeckt werden, die exponentiell steigen. Diese Art von „exponentiellen Kosten“ kommt häufig vor. Wenn wir einen Fehler beheben, können drei weitere Fehler folgen, allgemein bekannt als: Die Korrektur stürzt ab.

Daher können Fehler in frühen Unit-Tests gefunden werden, was nicht nur Zeit und Aufwand spart, die Effizienz im Entwicklungsprozess verbessert, sondern auch das Risiko und den Zeitaufwand für wiederholte Änderungen verringert.

3. Einige Missverständnisse über Unit-Tests

Zhihu https://zhuanlan.zhihu.com/p/547068206 2, 5, 6, 9, 11

Mythos 1: Unit-Tests verlangsamen den Entwicklungsprozess

Die Wahrheit ist: Wie bei jedem neuen Tool dauert es ein wenig, sich an Unit-Tests zu gewöhnen, aber insgesamt spart Unit-Tests Zeit und verschwendet weniger Zeit. Tatsächlich ermöglicht Ihnen die Durchführung von Regressionstests, den Entwicklungsprozess kontinuierlich und sorgenfrei voranzutreiben. Wenn Unit-Tests während der täglichen Builds durchgeführt werden, nehmen diese Tests keine Entwicklungszeit in Anspruch.

Missverständnis 2: Sobald das Projekt abgeschlossen ist, ist die in Unit-Tests investierte Arbeit verschwendet

Gar nicht. Wenn Sie jemals Code wiederverwendet haben, werden Sie erkennen, dass alles, was Sie tun, eine Bereicherung ist.

Tatsache ist: Wenn Sie Code, den Sie zuvor für ein anderes Projekt geschrieben haben, in einem Projekt verwenden oder diesen Code bearbeiten, können Sie dieselben Komponententests verwenden oder diese Komponententests bearbeiten. Es ist kein Problem, ähnliche Testcode-Snippets im selben Projekt zu verwenden.

Mythos 3: Unit-Tests sind Zeitverschwendung

Sie müssen herausfinden, was Zeitverschwendung ist?

Immer wieder die gleichen Schwachstellen beheben

Schreiben Sie während des gesamten Entwicklungsprozesses Validierungscode oder überschreiben Sie ihn neu

Ein Fehler wurde behoben, nur um aus dem Nichts an einer anderen Stelle ein weiterer Fehler aufzutauchen

Ich wurde beim Schreiben des Codes versehentlich unterbrochen und weiß nicht, was ich tun soll.

Der Widerstand gegen Unit-Tests ist verständlich, aber viele Entwickler werden die Qualität von Unit-Tests erst loben, wenn sie ein Projekt damit abgeschlossen haben.

Die Wahrheit ist: Sie müssen einen Unit-Test nur einmal schreiben, ihn aber mehrmals ausführen. Dies hat nichts mit Änderungen zu tun, die Sie an anderem Code vornehmen. Die Anfangsinvestition wird sich auf lange Sicht auszahlen.

Missverständnis 4: Unit-Tests helfen nicht beim Debuggen des Programms oder können das Auftreten von Schwachstellen nicht verhindern.

Das ist absolut nicht der Fall. Unit-Tests können das Debuggen von Programmen erleichtern, da Sie sich auf problematischen Code konzentrieren, die Probleme beheben und den geänderten Code dann erneut zusammenführen können. Es verhindert auch die Entstehung von Schwachstellen beim Hinzufügen von Funktionen und verhindert, dass Probleme wieder frustrierend auftreten, insbesondere bei der Programmierung mit einem objektorientierten Ansatz. Unit-Tests können keine hundertprozentige Beseitigung von Schwachstellen gewährleisten, sind aber eine gute Möglichkeit, Schwachstellen zu reduzieren.

Tatsache ist: Obwohl Unit-Tests nicht alle Probleme lösen können, die beim Debuggen auftreten, kann der isolierte Code im Unit-Test beim Auffinden einer Schwachstelle die Behebung der Schwachstelle erleichtern. Laut eingefleischten Fans von Unit-Tests unter Entwicklern besteht der größte Vorteil von Unit-Tests darin, dass es das Debuggen des Programms sehr einfach und unkompliziert macht.

Missverständnis 5: Die Verwendung von Unit-Tests zum Programm-Debuggen bietet keine umfassende Abdeckung

Nur weil Sie nicht den gesamten Code debuggen können, heißt das nicht, dass die Debugging-Abdeckung nicht umfassend ist. Die Verwendung von Unit-Tests zum Programm-Debuggen ist zumindest besser als andere Arten des Debuggens. Tatsächlich haben Unit-Tests einen ganz erheblichen Vorteil: Sie reduzieren die Anzahl der oben erwähnten gemeldeten Schwachstellen erheblich (wenn sie sie nicht sogar erheblich beseitigen). Das Reproduzieren von Fehlern kann beim Entwickeln und Debuggen von Programmen sehr frustrierend sein. Mit Unit-Tests können Sie die Häufigkeit der Einführung neuer Schwachstellen beim Hinzufügen, Ändern und Entfernen von Funktionen reduzieren. Das Debuggen war schon immer eine „vollständige Abdeckung“, insbesondere wenn die Geräte oder Systeme, auf denen das Programm läuft, sehr unterschiedlich sind.

Die Wahrheit ist: Insbesondere beim Umgang mit Schwachstellen können Unit-Tests sicherstellen, dass Sie Schwachstellen finden, die noch nie gemeldet wurden. Und wenn Sie das Programm debuggen, müssen Sie nicht den gesamten Code überprüfen, sondern nur die Stellen ändern, an denen Schwachstellen auftreten.

4. Was sind die gängigen Unit-Testing-Frameworks?

  1. Junit: Junit ist eines der am häufigsten verwendeten Java-Unit-Test-Frameworks. Es bietet eine Reihe einfacher und benutzerfreundlicher APIs zum einfachen Schreiben und Ausführen von Unit-Tests. Zu den Hauptvorteilen von Junit gehören die einfache Erlernbarkeit und Verwendung, die breite Nutzung, die reichhaltige Ökologie usw., es fehlen jedoch einige erweiterte Funktionen, wie z. B. simulierte Objekte usw.
  2. Mockito: Mockito ist ein Java-Unit-Test-Framework für Scheinobjekte, das Entwicklern hilft, Scheinobjekte für echte Unit-Tests zu erstellen und zu verwalten. Zu den Hauptvorteilen von Mockito gehören leistungsstarke Funktionen, einfache Erlernbarkeit und Verwendung, Unterstützung für Erweiterungen usw., es kann jedoch zu Leistungsproblemen kommen.
  3. Spock: Spock ist ein Java-Unit-Test-Framework, das auf der Groovy-Sprache basiert. Es bietet eine Reihe prägnanter und lesbarer DSL (domänenspezifischer Sprachen), mit denen Entwickler problemlos Unit-Tests schreiben und ausführen können. Zu den Hauptvorteilen von Spock gehören die einfache Lesbarkeit und Wartung, die Bereitstellung einer umfangreichen Assertionsbibliothek, die Unterstützung datengesteuerter Tests usw., es erfordert jedoch zusätzliche Unterstützung für den Groovy-Compiler. Die Kompatibilität ist jedoch relativ schlecht. Wenn die abhängige Version geringfügig falsch ist, werden einige unerklärliche Fehler gemeldet und die Eingabeaufforderungen sind nicht offensichtlich, was die Fehlerbehebung erschwert.
  4. TestNG: TestNG ist ein Java-Testframework, ähnlich wie Junit. Es bietet eine Reihe leistungsstarker Testfunktionen, einschließlich Unterstützung für Multithread-Tests, datengesteuerte Tests, Gruppentests usw. Zu den Hauptvorteilen von TestNG zählen umfangreiche Funktionalität, einfache Erweiterung und die Möglichkeit zur Integration mit verschiedenen kontinuierlichen Integrationstools. Es fehlen jedoch einige erweiterte Funktionen, wie z. B. Scheinobjekte.
  5. PowerMock: PowerMock ist ein Erweiterungsframework für Java-Unit-Tests, das Entwicklern hilft, flexiblere Unit-Tests zu schreiben. Zu den Hauptvorteilen von PowerMock gehört die Unterstützung für das Testen statischer Methoden, privater Methoden usw., die einfache Erlernbarkeit und Verwendung sowie die Verwendung mit anderen Test-Frameworks usw., die jedoch möglicherweise zu mehr Komplexität und Wartungskosten führen.

5. Beispiele für die Verwendung jedes Frameworks

JUnit:

import org.junit.Test;
import static org.junit.Assert.*;

public class MyTest {
    
    
    @Test
    public void testSomething() {
    
    
        // 执行测试代码
        assertEquals(2 + 2, 4);
    }
}

Mockito:

import static org.mockito.Mockito.*;

public class MyTest {
    
    
    @Test
    public void testSomething() {
    
    
        // 创建模拟对象
        MyObject mockObject = mock(MyObject.class);
        // 设置模拟对象的行为
        when(mockObject.someMethod()).thenReturn("Hello World");
        // 执行测试代码
        String result = mockObject.someMethod();   
        // 断言结果是否符合预期
        assertEquals(result, "Hello World");
    }
}

Spock:

import spock.lang.Specification
import spock.lang.Subject

class CalculatorSpec extends Specification {
    
    

    @Subject
    Calculator calculator = new Calculator()

    def "test add method"() {
    
    
        given:
        int a = 2
        int b = 3

        when:
        int result = calculator.add(a, b)

        then:
        result == 5
    }

    def "test subtract method"() {
    
    
        given:
        int a = 5
        int b = 2

        when:
        int result = calculator.subtract(a, b)

        then:
        result == 3
    }
}

class Calculator {
    
    
    int add(int a, int b) {
    
    
        return a + b
    }

    int subtract(int a, int b) {
    
    
        return a - b
    }
}

TestNG:

import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import static org.testng.Assert.assertEquals;

public class MyTestNGTest {
    
    
    
    @BeforeMethod
    public void setUp() {
    
    
        // 在测试方法执行前执行的代码
    }
    
    @AfterMethod
    public void tearDown() {
    
    
        // 在测试方法执行后执行的代码
    }
    
    @Test
    public void testAddition() {
    
    
        int result = Calculator.add(2, 3);
        assertEquals(result, 5);
    }
    
    @Test
    public void testSubtraction() {
    
    
        int result = Calculator.subtract(5, 3);
        assertEquals(result, 2);
    }
}

class Calculator {
    
    
    public static int add(int a, int b) {
    
    
        return a + b;
    }
    
    public static int subtract(int a, int b) {
    
    
        return a - b;
    }
}

PowerMock:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Example.class)
public class ExampleTest {
    
    

    @Test
    public void testPrivateMethod() throws Exception {
    
    
        Example spy = spy(new Example());
        doReturn("mocked value").when(spy, "privateMethod");

        String result = spy.publicMethod();
        assertEquals("mocked value called from publicMethod", result);
    }
}

class Example {
    
    
    public String publicMethod() throws Exception {
    
    
        return privateMethod() + " called from publicMethod";
    }

    private String privateMethod() {
    
    
        return "privateMethod";
    }
}

Das Obige ist nur ein einfaches Beispiel. Bei der tatsächlichen Verwendung ist es erforderlich, Testcode entsprechend der spezifischen Situation zu konfigurieren und zu schreiben.

6. Vergleich verschiedener Frameworks

Rahmen und Funktionen Scheinfunktion Unterstützen Sie private und statische Methoden Lesbarkeit des Codes Lernkosten grammatikalische Konzepte Skalierbarkeit und Anpassung Integration und Kompatibilität Dokumentation und Community-Unterstützung Leistung und Stabilität
Junit × × Hohe Lesbarkeit Niedrig Einfach und leicht verständlich Arm Der Federtest ist standardmäßig integriert Gut Gut
Mockito × Hohe Lesbarkeit Niedrig Einfache API, hervorragende Dokumentation Arm Der Federtest ist standardmäßig integriert Gut Gut
TestNg × Durchschnittliche Lesbarkeit Mittel Einfache Syntax, aber umständliche Abhängigkeitskonfiguration Bietet eine Fülle von Erweiterungspunkten und Plug-in-Mechanismen Gut Im Allgemeinen gibt es relativ wenig Dokumentation Gut
PowerMock Der Code ist lang und komplex und nicht sehr gut lesbar Mittel Die Syntax ist relativ komplex Bietet eine Fülle von Erweiterungspunkten und Plug-in-Mechanismen Gut Gut Gut
Spock Sie müssen die Groovy-Syntax kennen hoch Basierend auf Groovy-Sprache, komplexer Syntax Bietet eine Fülle von Erweiterungspunkten und Plug-in-Mechanismen Schlechte Kompatibilität Gut Gut

Zusammenfassung: Es wird empfohlen, Junit+Mockito zu verwenden

  • Junit und TestNG werden hauptsächlich für Integrationstests verwendet. PowerMock und Spock weisen hohe Lernkosten, lange Codes und eine komplizierte Lesbarkeit auf, was dem Lesen nicht förderlich ist.
  • Es verfügt über eine einfache API, eine hervorragende Dokumentation und eine große Anzahl von Beispielen, was den Einstieg erleichtert und die Codekomplexität nicht hoch ist.
  • Es ist gut lesbar, der Code ist einfach und leicht zu verstehen, es wird von der Community gut unterstützt und es ist leicht, Lösungen zu finden, wenn Probleme auftreten.
  • spring-boot-starter-test integriert standardmäßig die Frameworks Junit und Mockito.
  • Private und statische Methoden können mit einer Kombination aus Junit, PowerMock und Mockito verspottet werden.

7. Wie führt man einen einzelnen Test durch?

1. Nutzungsszenarien für einzelne Tests

  1. Code-Wiederverwendungsrate . Je höher die Wiederverwendungsrate des Codes ist, desto notwendiger ist es, Einzeltests zu implementieren und desto notwendiger ist es, die Anforderungen für Einzeltests zu verbessern. Daher werden diese Codes von vielen Unternehmen referenziert. Sobald Probleme auftreten, wirken sich diese auf viele Geschäftsparteien aus. Es ist rentabler, einzelne Tests für solche Codes durchzuführen.
  2. Geschäftsänderungsrate . Je schneller sich das Unternehmen verändert, desto weniger eignet sich der Einsatz von Einzeltests. Wenn sich das Unternehmen sehr schnell ändert und der Inhalt eines einzelnen Tests innerhalb weniger Tage nach der Online-Veröffentlichung geändert werden muss, müssen Sie nicht nur den Geschäftscode, sondern auch den einzelnen Testcode ändern, was den doppelten Arbeitsaufwand bedeutet.
  3. Personalfluktuationsrate . Unter der Personalwechselrate versteht man den Wechsel der Verantwortlichen eines bestimmten Moduls. Wenn der Verantwortliche eines bestimmten Moduls häufig wechselt, ist es nicht für Einzeltests geeignet. Da der neue Verantwortliche viel Zeit damit verbringen muss, sich mit den Inhalten des einzelnen Tests vertraut zu machen, wird die Entwicklungszeit der Anforderungen sehr lang.
  4. Geschäftliche Bedeutung . Je zentraler das Unternehmen, desto notwendiger ist die Implementierung einzelner Tests und desto notwendiger ist die Einhaltung hoher Standards. Denn die Stabilität und Robustheit des Kerngeschäfts sind für das Unternehmen auf jeden Fall sehr wichtig und einzelne Tests können tatsächlich die Systemstabilität und Systemrobustheit in der kleinsten Einheit verbessern.

Wir können die vier oben genannten Messdimensionen nicht isoliert betrachten, sondern müssen umfassende, auf der tatsächlichen Situation basierende Urteile fällen, um zum am besten geeigneten Standard zu gelangen!

2. Gute Unit-Tests müssen den Prinzipien entsprechen.

①AIR-Prinzip

Hinweis: Wenn der Unit-Test online ausgeführt wird, fühlt es sich an wie Luft (AIR), aber es ist sehr wichtig, die Qualität des Tests sicherzustellen. Aus makroökonomischer Sicht zeichnen sich gute Unit-Tests durch Automatisierung, Unabhängigkeit und wiederholbare Ausführung aus.

  • A : Automatische Unit-Tests sollten vollständig automatisiert und nicht interaktiv sein. Testfälle werden in der Regel regelmäßig ausgeführt und der Ausführungsprozess muss vollständig automatisiert sein, um sinnvoll zu sein. Ein Test, dessen Ausgabe eine manuelle Überprüfung erfordert, ist kein guter Komponententest.
  • I : Unabhängig (Unabhängigkeit) behält die Unabhängigkeit von Unit-Tests bei. Um sicherzustellen, dass Unit-Tests stabil, zuverlässig und leicht zu warten sind, dürfen sich Unit-Testfälle nicht gegenseitig aufrufen und können sich auch nicht auf die Ausführungsreihenfolge verlassen. Gegenbeispiel : Methode2 muss sich auf die Ausführung von Methode1 verlassen und das Ausführungsergebnis wird als Parameter von Methode2 eingegeben.
  • R : Wiederholbare (wiederholbare) Komponententests können wiederholt ausgeführt werden und können nicht durch die externe Umgebung beeinflusst werden. Hinweis : Unit-Tests werden normalerweise in der kontinuierlichen Integration platziert und Unit-Tests werden jedes Mal ausgeführt, wenn Code eingecheckt wird. Wenn ein einzelner Test von der externen Umgebung (Netzwerk, Dienst, Middleware usw.) abhängt, führt dies leicht dazu, dass der kontinuierliche Integrationsmechanismus nicht verfügbar ist. Positives Beispiel : Um nicht von der externen Umgebung beeinflusst zu werden, ist es erforderlich, beim Entwerfen des Codes die SUT-Abhängigkeit in Injektion zu ändern und beim Testen ein DI-Framework wie Spring zu verwenden, um eine lokale (Speicher-)Implementierung oder eine Mock-Implementierung zu injizieren .

②ERSTES Prinzip

1. F-Fast (schnell)

Unit-Tests sollten schnell ausgeführt werden können. Unter den verschiedenen Testmethoden laufen Unit-Tests am schnellsten. Unit-Tests für große Projekte sollten normalerweise innerhalb weniger Minuten ausgeführt werden.

2. Ich-unabhängig (unabhängig)

Unit-Tests sollten unabhängig voneinander ausgeführt werden können. Unit-Testfälle sind weder voneinander noch von externen Ressourcen abhängig.

3. R-Repeatable (wiederholbar)

Unit-Tests sollten stabil und wiederholt ausgeführt werden können und die Ergebnisse jedes Durchlaufs sollten stabil und zuverlässig sein.

4. S-SelfValidating (selbstverifizierend)

Unit-Tests sollten automatisch anhand von Anwendungsfällen überprüft werden und können nicht auf einer manuellen Überprüfung beruhen.

5. T-Timely

Unit-Tests müssen zeitnah geschrieben, aktualisiert und gewartet werden, um sicherzustellen, dass Anwendungsfälle die Qualität dynamisch garantieren können, wenn sich der Geschäftscode ändert.

3. Schreiben Sie Unit-Testcode gemäß den BCDE-Prinzipien, um die Lieferqualität des getesteten Moduls sicherzustellen.

  • B : Grenze, Grenzwertprüfung, einschließlich Schleifengrenzen, Sonderwerte, Sonderzeitpunkte, Datenreihenfolge usw.
  • C : Korrigieren Sie die Eingabe und erhalten Sie die erwarteten Ergebnisse.
  • D : Design, kombiniert mit Designdokumenten, um Unit-Tests zu schreiben.
  • E : Fehler, der die Eingabe von Fehlerinformationen erzwingt (z. B. illegale Daten, abnormale Prozesse, nicht für Unternehmen zulässige Eingaben usw.) und das Erzielen der erwarteten Ergebnisse.

4. Welche Szenarien erfordern das Schreiben einzelner Tests?

Der inkrementelle Code von Kerngeschäft, Kernanwendungen und Kernmodulen stellt sicher, dass Unit-Tests bestanden werden.

Unit-Tests sind das grundlegendste Mittel der Softwareentwicklung, und eine der wichtigsten Ideen in der Softwareentwicklung ist die Idee der Schichtung. Jedes High-Level-Modul besteht aus mehreren Low-Level-Modulen. Wenn es mit einigen instabilen Low-Level-Modulen zusammengesetzt wird, werden auch die High-Level-Module unzuverlässig. Genau wie im Reich der Mathematik gibt es mehrere grundlegende Axiome, die streng Schicht für Schicht durch Beweise aufgebaut werden. Darüber hinaus sollten wir beim Schreiben von Geschäften mehr auf das mehrschichtige Denken des traditionellen dreischichtigen Modells von Controller, Service und Dao achten, anstatt dogmatisch zu sagen, dass alle Unternehmen diese drei Schichten haben. Ausgehend von der hierarchischen Idee als Leitideologie gibt es komplexere Geschäftsebenen und weniger einfache Geschäftsebenen.

Controller -> Dienst -> Externe Schnittstelle des Managers

— - - - - - - - - - - - - -> Dao-Datenbank

Controller: Verantwortlich für die Annahme von Anfragen und die Rückgabe von Antworten sowie für die einfache Überprüfung von Parametern. Für Logik ohne Verifizierung ist kein einzelner Test erforderlich. Komplexe Verifizierungslogik erfordert einzelne Tests. Wird hauptsächlich für Integrationstests verwendet

Dienst: dient als Baustein. Er ist für die Organisation der Geschäftslogik, die Verarbeitung der Geschäftslogik, die Verarbeitung von Anforderungen von der Controller-Schicht und den Zugriff auf die DAO-Schicht und den Manager verantwortlich. Er muss einzelne Tests schreiben.

Manager: ① Verantwortlich für die Koordinierung mehrerer Service-Layer-Komponenten und die Verarbeitung von Interaktionen zwischen Service-Layern, die einzelne Tests erfordern. ②Kapseln Sie die externe Schnittstelle und ohne zusätzliche Verarbeitungslogik ist kein einzelner Test erforderlich. ③Die Interaktion mit der Dao-Schicht und die Steuerung von Transaktionen erfordern einzelne Tests.

Dao: Datenbankbezogene Vorgänge ausführen. Komplexe Logik erfordert das Schreiben einzelner Tests, die ausschließlich dem Abrufen von Daten oder der Aktualisierung dienen, und im Grunde werden keine einzelnen Tests durchgeführt.

Wie führt man einzelne Tests der DAO-Schicht durch, ohne die Testdatenbank zu verschmutzen?

  1. Eingebettete Datenbanken verwenden: Sie können eingebettete Datenbanken wie H2, HSQLDB usw. für Unit-Tests verwenden. Diese eingebetteten Datenbanken können im Speicher ausgeführt werden und belasten daher nicht die Daten in der Produktionsdatenbank.

  2. Transaktions-Rollback verwenden: Sie können das Transaktions-Rollback verwenden, um sicherzustellen, dass der Test die Daten in der Datenbank nicht verunreinigt. Bevor die Testmethode startet, wird eine Transaktion gestartet. Nach Abschluss des Tests wird die Transaktion zurückgesetzt, sodass alle geänderten Daten in den Zustand vor dem Test zurückversetzt werden, wodurch eine Datenverschmutzung vermieden wird. (Empfohlene Nutzung)

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserServiceTest {
          
          
    
        @Autowired
        private UserService userService;
    
        @Test
        @Transactional
        public void testAddUser() {
          
          
            User user = new User();
            user.setName("John Doe");
            userService.addUser(user);
    
            // perform assertion
            User savedUser = userService.getUserByName(user.getName());
            Assert.assertNotNull(savedUser);
        }
    }
    
  3. Verwenden Sie Datenbankmigrationstools: Sie können Datenbankmigrationstools wie Flyway, Liquibase usw. für Unit-Tests verwenden. Diese Tools können vor jedem Test automatisch eine neue Datenbankinstanz erstellen und Datenbankmigrationsskripte verwenden, um die Daten zu initialisieren, wodurch das Problem der Datenverschmutzung vermieden wird.

  4. Erstellen Sie ein Docker-Image und starten Sie eine Datenbank.

Kurz gesagt besteht der Zweck des Schreibens von Unit-Tests darin, die Richtigkeit und Zuverlässigkeit jedes Moduls sicherzustellen. Erst wenn jedes Modul durch Unit-Tests verifiziert wurde, kann es zu einem stabilen und zuverlässigen Ganzen kombiniert werden.

8. Diskussionsfragen:

1. In Legacy-Projekten ist der Code verwirrend und es ist schwierig, einzelne Tests zu schreiben, und er kann nicht umgedreht und neu geschrieben werden. Wie fügt man einzelne Tests elegant hinzu?

2. Wenn sich nach dem Schreiben des Komponententests die Funktion ändert, sollten Sie dann zuerst den Code ändern oder den Komponententest schreiben?

Testen und Codieren können mit zwei menschlichen Beinen verglichen werden. Es stellt sich also die Frage: Soll ich zuerst mit dem linken oder dem rechten Bein gehen? Ich denke, jeder wird denken, dass die Antwort auf diese Frage bedeutungslos ist, aber wenn Sie darüber nachdenken, vorsichtig zu gehen, werden Sie feststellen, dass die Koordination des linken und rechten Beins der Schlüssel zum Gehen ist. Wenn die Schritte lang sind, ist es ein Bein lahm oder ein Fuß hüpft, sie sind alle in einem schlechten Zustand. Analog zum Unit-Test gilt dasselbe wie testgetriebenes Codieren und Codierungsoptimierungstests. Aufgeblähtes Codieren ist wie ein zu großer Schritt; ein schlechter einzelner Test bedeutet, dass ein Bein lahm ist; wenn Sie keinen einzigen Test schreiben, ist es ein einbeiniges Spiel.

Supongo que te gusta

Origin blog.csdn.net/Edward_hjh/article/details/129670775
Recomendado
Clasificación