[JAVA] Schreiben Sie den Testcode mit Spring Boot

Überblick

Ich habe den Testcode für die MVC-bezogene Verarbeitung und die Login-bezogene Verarbeitung in Spring Boot durch Ausprobieren geschrieben, daher werde ich ihn als Memorandum zusammenfassen.

Wenn Sie wissen, wie man besser schreibt, wäre ich Ihnen dankbar, wenn Sie mir dies freundlicherweise beibringen könnten (╹◡╹)

Der Quellcode ist auf GitHub verfügbar.

Vorwort, das ohne Lesen verwaltet werden kann (zum Öffnen und Schließen klicken) Heutzutage höre ich oft, dass es besser ist, Testcode zu schreiben. Ich fragte mich, ob ich es schreiben sollte, aber als ich es nachschlug, hörte es beim Test der Berechnungsstufe mit vier Regeln auf. Wie sollte ich es also in der eigentlichen Anwendung schreiben ...!? Ich war nicht bereit, den Testcode zu schreiben.
Ich dachte, es wäre unangenehm, so wie es ist, also opferte ich Obon Urlaub und schrieb den Testcode durch Versuch und Irrtum, während ich bei Spring Boot unter Fehlern litt. Es gibt viele Punkte, die ich noch nicht verstehen konnte, aber vorerst habe ich bis zu einem gewissen Grad so etwas wie ein "Schreibmuster" etabliert, deshalb möchte ich es als Memorandum zusammenfassen.
Es gibt nicht viele Artikel über Spring Boot-Testcode, die systematisch sowohl in Japanisch als auch in Englisch organisiert sind. Es gibt also viele tastende Teile, aber ich hoffe, es hilft Ihnen, auch nur ein wenig zu verstehen ('ω').

Ziel Leser / Ziele

Dieser Artikel befasst sich mit dem Schreiben von Testcode in Spring Boot. Wenn Sie also die folgenden Punkte erfüllen, ist dies schmerzhaft.

Mit den oben genannten Annahmen können Sie durch das Lesen dieses Artikels (wahrscheinlich):

Außerdem sind diesmal die Bildschirmanzeige und der Test des JS-Teils usw. ausgeschlossen. In Zukunft habe ich vor, auch diesen Bereich abzudecken, aber plötzlich wäre es zu kompliziert, alles zu testen, also beginne ich mit einem kleinen Teil. Step up ist wichtig.

Ergänzung: Wie weit wird der Test automatisch durchgeführt (zum Öffnen und Schließen klicken) Die Wichtigkeit des Schreibens von Testcode wird oft erwähnt, aber das Ersetzen manueller Tests durch automatisierte Tests erfordert viel Erfahrung und Kosten.
Bei Geschäftsanwendungen gibt es verschiedene Dinge, die es schwierig machen, automatisierte Tests zu integrieren. Selbst wenn es keine Einschränkungen in der persönlichen Entwicklung gibt, ist plötzlich alles automatisiert !! Wenn ich mich beeile, ist mein Herz fast gebrochen (ich habe ƪ (˘⌣˘) ʃ gebrochen).
Daher halte ich es für eine schmerzhafte Möglichkeit, sich auf den Teil "Was kann durch den automatischen Test erreicht werden" zu konzentrieren und den Teil, der automatisch getestet werden kann, schrittweise so weit wie möglich zu erhöhen. Das Schreiben von Testcode erfordert ein gründliches Verständnis des Frameworks und der Sprache. Ich denke, es ist am besten, lange bei ihnen zu bleiben, wenn Ihre technischen Fähigkeiten zunehmen.

Kommen wir nun zum Umfang dieses Testcodes zurück. Wenn ich viele Apps mit Spring Boot schreibe, habe ich (persönlich) viele Fehler in den folgenden Bereichen festgestellt.
-Der erwartete Wert wird nicht an das an View übergebene Modell übergeben. -Wenn ich mir das Ausführungsergebnis der Dao-Layer-Verarbeitung in der DB anschaue, ist es nicht wie erwartet -Die Verarbeitung gemäß der Autorität des Benutzers funktioniert nicht wie erwartet
Das Obige überschneidet sich gut mit dieser Berichterstattung. Zunächst möchte ich die Freude an der Entwicklung steigern, indem ich es möglich mache, die Teile, die viele Fehler aufweisen und es schwer haben, effizient zu debuggen.

Ein einfaches Diagramm der obigen Abdeckung ist wie folgt.

image.png

Ich werde den Bereich berühren, von dem Zeitpunkt, an dem die Anfrage gesendet wird, bis zu dem Zeitpunkt, an dem View aufgefordert wird, sie anzuzeigen. Daher ist View diesmal im Grunde eine gute Nacht.

Umgebung

Weitere Informationen finden Sie unter GitHub pom.xml.

pom.xml(Auszug)


        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
		<dependency>
		    <groupId>org.junit.jupiter</groupId>
		    <artifactId>junit-jupiter-api</artifactId>
		    <scope>test</scope>
		</dependency>
		<dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.dbunit/dbunit -->
		<dependency>
		    <groupId>org.dbunit</groupId>
		    <artifactId>dbunit</artifactId>
		    <version>2.5.1</version>
		    <scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.github.springtestdbunit/spring-test-dbunit -->
		<dependency>
		    <groupId>com.github.springtestdbunit</groupId>
		    <artifactId>spring-test-dbunit</artifactId>
		    <version>1.3.0</version>
		    <scope>test</scope>
		</dependency>

Testbereich

Nun wollen wir sehen, wie der Testcode von hier aus tatsächlich geschrieben wird. Da der Spring Boot-Testcode jedoch durch Kombination einiger Kenntnisse geschrieben wird, steigt der Schwierigkeitsgrad, wenn Sie versuchen, alles auf einmal abzudecken.

Daher möchte ich es in die folgenden vier Schritte unterteilen.

Die in diesem Artikel behandelte Abdeckung der Stufen 1 bis 3 wird grob wie folgt dargestellt.

image.png

Beginnen wir mit Hello World.


Level1. Teste Hello World

Dies ist die vertraute Hallo Welt. Schauen wir uns einige gängige Prozesse an, z. B. wenn eine Anfrage an "/ hello / init" unten gestellt wird, wird "hello" als Ansichtsname zurückgegeben.

HelloController.java


@Controller
@RequestMapping("/hello")
public class HelloController {
	
	@RequestMapping("/init")
	private String init() {
		return "hello";
	}
}

Es ist einfach zu tun, erfordert jedoch einige neue Kenntnisse, um Testcode zu schreiben. Daher ist es ein sehr wichtiger Teil des Einstiegs in den Spring Boot-Testcode.

Erstens ist der Code selbst nicht sehr lang. Um einen Überblick zu erhalten, schreiben Sie den tatsächlichen Testcode unten.

HelloControllerTest.java


@AutoConfigureMockMvc
@SpringBootTest(classes = DbMvcTestApplication.class)
public class HelloControllerTest {
	
	//mockMvc Mock-Objekt zur Verarbeitung von HTTP-Anforderungen und -Antworten ohne Bereitstellung auf dem Tomcat-Server
	@Autowired
	private MockMvc mockMvc;
	
	//Geben Sie die Ansicht in get request an und beurteilen Sie den Erfolg / Misserfolg der Anfrage anhand des http-Status
	@Test
Die Verarbeitung von void init wird ausgeführt und gibt 200 zurück() throws Exception {
		// andDo(print())Anfrage / Antwort mit anzeigen
		this.mockMvc.perform(get("/hello/init")).andDo(print())
			.andExpect(status().isOk());
	}

Als ich plötzlich eine App schrieb, fand ich viele Dinge, mit denen ich nicht vertraut war. Die Verarbeitung dieses Testcodes ist grob in "zwei" Blöcke unterteilt. Schauen wir uns also die einzelnen Blöcke genauer an.

Klassenanmerkung

Die der Klasse gegebenen Anmerkungen enthalten wichtige Informationen, um ein Gesamtbild des Testcodes zu erhalten. Ich benutze es normalerweise nicht, aber wenn Sie einen guten Überblick bekommen, wird der Abstand zum Testcode verkürzt.

AutoConfigureMockMvc-Annotation

Es ist eine Anmerkung, etwas namens "MockMvc" zu verwenden. Wer ist MockMvc?

Dies dient dazu, den physischen "Server" von der erstellten "Webanwendung" zu trennen. Es kommt nicht sehr gut heraus, also schauen wir uns an, was uns glücklich macht, indem wir es trennen.

Ergänzung: Sie müssen Mock verwenden (zum Öffnen und Schließen klicken) Einer der Vorteile der Verwendung eines Modells ist die Verkürzung der Ausführungszeit des Testcodes. Die Begrenzung des Wirkungsbereichs ist jedoch auch ein wichtiger Faktor.
Wenn zum Beispiel beim Testen der Verarbeitung der Service-Schicht, die auf die Dao-Schicht zugreift, ein einfacher Prozess ist, denke ich, dass der Test ohne großen Aufwand ohne Verwendung eines Modells realisiert werden kann. Wenn der Code jedoch kompliziert wird und die Personen, die ihn erstellen, unterschiedlich sind, muss bei Auftreten eines Fehlers untersucht werden, ob die Ursache in der "Service-Schicht" oder der "Dao-Schicht" liegt. Es wird sein. Wenn hier die Dao-Schicht "angemessen" verspottet wird und der Service-Schicht-Test zuerst abgeschlossen wird und ein Problem beim Ersetzen durch die tatsächliche Klasse auftritt, kann die Ursache auf die Dao-Schicht beschränkt werden. Es wird möglich sein.
Selbst wenn Sie in der persönlichen Entwicklung kein Mock verwenden, müssen Sie alles von 1 bis 100 selbst implementieren, sodass Sie möglicherweise nicht viele Möglichkeiten haben, Mock für andere Zwecke als die Reduzierung der "Ausführungszeit" zu verwenden. Die Idee, den Einflussbereich zu beschränken, der nicht auf den Testcode beschränkt ist, wird jedoch wichtig, und in der Teamentwicklung wird nicht alles von selbst erstellt, sodass die Idee und der Umgang mit Mock auch auf der Übersichtsebene liegen. Ich denke du solltest es wissen.
Ich kann jedoch nicht sagen, dass ich das Modell vollständig verwenden kann. Wenn Sie also eine bessere Denkweise kennen, würde ich mich sehr freuen, wenn Sie es mir sagen könnten. Das Folgende ist ein Referenzmaterial. [Was ist ein Mock-Objekt?](Https://www.itmedia.co.jp/im/articles/1111/07/news180.html) [Vorteile von Mock](https://stackoverflow.com/questions/22783772/what-is-the-benefits-of-mocking-the-dependencies-in-unit-testing)

Bei der persönlichen Entwicklung wird der Serverteil verspottet, um die Ausführungszeit des Testcodes zu verkürzen, und bei der Teamentwicklung wird der nicht beteiligte Teil verspottet und der Testcode wird geschrieben, nachdem der Einflussbereich begrenzt wurde. Ich denke, es ist besser, fortzufahren.

Das Folgende ist ein Referenzmaterial.

Japanisches Material von MockMvc Offizieller Web Layer Test


SpringBootTest-Annotation

Dies ist eine Anmerkung, die sehr wichtig zu sein scheint. Es ist eigentlich eine sehr wichtige Anmerkung. Im Unit-Test von Spring Boot handelt es sich um eine Anmerkung, die fast immer angezeigt wird und viele Funktionen hat. Daher möchte ich die Funktionen Schritt für Schritt betrachten.

Die folgenden zwei Funktionen sind hier wichtig.

Lassen Sie uns zunächst über die Annotation "ExtendWith" sprechen. Die RunWith-Annotation wurde häufig in der Erläuterung des Spring Boot-Tests verwendet, aber die "RunWith-Annotation" ist eine Annotation für Junit4 und die ExtendWith-Annotation ist eine Annotation für Junit5.

Es wird für die allgemeine Implementierung der Testvorverarbeitung und -nachverarbeitung verwendet. Anschließend wird SpringExtension an die Klasse "Extension" übergeben, bei der es sich um die value-Eigenschaft handelt, und die Implementierung der allgemeinen Verarbeitung wird geschrieben. Dies ist eine evolutionäre Geschichte, daher werde ich sie diesmal weglassen, aber diese Erweiterungsklasse spielt eine wichtige Rolle, beispielsweise bei der Instanziierung eines ApplicationContext, der als DI-Container fungiert. Weitere Informationen finden Sie unter Offiziell.

Nun, wie ich schon lange geschrieben habe, ist die Verwendung eines DI-Containers mit Spring Boot nicht mehr selbstverständlich, und es ist mühsam, jedes Mal eine ExtendWith-Annotation zu schreiben. Wie Sie der Dokumentation entnehmen können, ist es selbstverständlich, sie zu verwenden. Wenn dies der Fall ist, kann es eingeschlossen werden, sodass nur die SpringBootTest-Annotation in Ordnung ist.

Durch das Erstellen einer Anmerkung, die auf diese Weise mehrere Funktionen enthält, ist es möglich, die Beschreibung der Prämisse des Testcodes zu vereinfachen. Dieses Mal werden wir jedoch die Verständlichkeit für die Integration hervorheben Anmerkungen werden weggelassen.


Schauen wir uns als nächstes die ApplicationContext-Einstellungen an. ApplicationContext wird oft als Wort verwendet, aber ich denke, es ist in Ordnung, wenn Sie es als "DI-Container" betrachten.

Es ist nicht möglich, alles durch einfaches Bestehen der Hauptklasse zu lösen, aber ich möchte dies im Bereich des Testens auf der Dao-Ebene ansprechen, für die keine HTTP-Anforderung / Antwort erforderlich ist.

Ergänzung: Was an die Klasseneigenschaft übergeben werden soll (zum Öffnen / Schließen klicken) Wie Sie in der Dokumentation (https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html#classes--) sehen können, ist die Eigenschaft "classes" Die eingestellte Klasse hat die Rolle "Konfiguration" und wird zur Realisierung des DI-Containers verwendet. In der vorherigen Erklärung hat die mit der SpringBootApplication-Annotation die "Einstellung" für den DI-Container realisiert.
Diesmal hängt HelloController jedoch nicht von anderen Klassen ab (soweit Sie sehen können). Selbst wenn Sie "HelloController" an die Eigenschaft "classes" übergeben, funktioniert dies. Da jedoch davon ausgegangen wird, dass der Eigenschaft "classes" ursprünglich eine Klasse übergeben wurde, die eine Rolle als Einstellungsklasse hat, wird eine Klasse mit der Annotation SpringBootApplication oder eine Konfigurationsklasse verwendet, die die zum Testen erforderlichen Einstellungen definiert. Es wäre besser, es zu bestehen. Wenn Sie bei der Verwendung einer Funktion zumindest die im Dokument beschriebenen Parameter lesen, sind Sie von unerwartetem Verhalten abhängig und ratlos. Ich denke das wird weniger sein. (Selbstdisziplin)
* Wenn nur HelloController als WebApplicationContext definiert ist, ist der Body-Teil der Antwort von MockMvc leer. (Der Inhalt wurde nicht gesehen, aber es scheint, dass die Ursache darin besteht, dass ViewResolver und View nicht instanziiert werden.)

Die Erklärung ist nur durch das Einstellen lang geworden, aber sobald Sie sie verstanden haben, ist sie ein wichtiger Teil, der beim Schreiben anderer Testcodes verwendet werden kann. Daher kann es sinnvoll sein, sich hinzusetzen und zu studieren. .. (Ich habe verstanden, dass ich DI überhaupt nicht verstanden habe, daher war es eine gute Gelegenheit, Spring zu überprüfen.)

Testcode

Endlich bin ich zum eigentlichen Testcode gekommen. Es ist einfacher und macht mehr Spaß als die bisherigen detaillierten Einstellungen. Nachdem es eine Lücke gibt, schauen wir uns noch einmal den Teil an, der sich auf den Testcode bezieht.

HelloControllerTest.java(Auszug)


//Geben Sie die Ansicht in get request an und beurteilen Sie den Erfolg / Misserfolg der Anfrage anhand des http-Status
    @Test
Die Verarbeitung von void init wird ausgeführt und gibt 200 zurück() throws Exception {
        // andDo(print())Anfrage / Antwort mit anzeigen
        this.mockMvc.perform(get("/hello/init")).andDo(print())
            .andExpect(status().isOk());
    }

Der obige Testcode führt zwei Prozesse aus, "Ausführung der Anforderung" und "Überprüfung der Antwort".

Beide Prozesse werden basierend auf der Instanz von "MockMvc" ausgeführt und im Wesentlichen in einer Anweisung wie oben beschrieben beschrieben. Indem Sie sie in einem Satz zusammenfassen, können Sie in Form eines englischen Satzes herausfinden, was der Test tut. Mal sehen, wie es tatsächlich geschrieben ist.

Um das Obige zusammenzufassen, lautet der englische Text wie folgt. (Ich kann nicht sehr gut schreiben, also fühle es bitte in der Atmosphäre ƪ (˘⌣˘) ʃ)

Perform get request to [/hello/init] and print the result, and I expect that status is 200 OK.

Da die Programmiersprache in Englisch geschrieben ist, besteht natürlich der Vorteil, dass englische Muttersprachler Testcode in einer Struktur lesen und schreiben können, die den gewohnten englischen Sätzen ähnelt. (Es scheint keine Möglichkeit zu geben, dem Englischen zu entkommen, daher kann es nicht schmerzhaft sein, wenn Sie zumindest so lesen und zuhören, wie es ist.)

Es ist ein wenig abseits des Themas, aber wenn Sie die Testmethode und die erwarteten Ergebnisse in einem einfach zu lesenden Format beschreiben, können Sie leicht wichtige Informationen aus dem Testcode abrufen, um die Systemspezifikationen und den tatsächlichen Quellcode zu verstehen. Werden. Wenn Sie es umdrehen, wird Testcode, der nicht den Spezifikationen entspricht, den Fehler übersehen und nicht zum Verständnis der Spezifikationen führen, sodass es sich um nutzlosen Code handelt.

In einer so einfachen Codephase kann es sinnvoll sein, sich daran zu gewöhnen, Testcode zu schreiben, während man sich immer darüber im Klaren ist, "was als Funktion im implementierten Prozess realisiert werden sollte".

Nach langem Hin und Her lautet die Anforderungsantwort, wenn HelloWorld mit dem Testcode überprüft wird, wie folgt. image.png

image.png

Sie sollten bestätigen können, dass die oben beschriebenen Inhalte erfüllt sind.

Schließlich kann ich bestätigen, dass Hello World ordnungsgemäß funktioniert. Ich habs gemacht.


Testen Sie das Modell

Da es eine Grenze gibt, was allein mit dem HelloWorld-Testcode überprüft werden kann, möchte ich die Modellüberprüfung als eine weitere praktische Sache auf Stufe 1 betrachten.

Das Modell bezieht sich hier auf "Java-Objekt, auf das von View verwiesen wird" und wird häufig in "Model.addAttribute" usw. geschrieben. Es kommt sehr häufig vor, dass ich dachte, ich würde den Wert gut in das Modell einfügen, aber er war nicht darin, sodass ich den Server nicht starten und mit einem Klick auf den Bildschirm zugreifen musste ... Es wäre sehr praktisch, wenn wir überprüfen könnten, ob es funktioniert.

Im Folgenden erfahren Sie, wie Sie den Inhalt des Modells mit Testcode überprüfen können. Der Inhalt ist leichter zu verstehen als die, die ich bisher angesprochen habe. Ich hoffe, Sie beherrschen die Verwendung.


Zu überprüfender Code

Schauen wir uns zunächst den zu testenden Code an. Das heißt, es ist nur eine kleine Erweiterung von HelloController, und es ist nicht so schwierig, also werde ich hier alles auf einmal setzen.

HelloController.java


@Controller
@RequestMapping("/hello")
public class HelloController {
	
	@RequestMapping("/init")
	private String init(Model model) {
		
		//Benutzerliste Zuerst manuell generieren
		List<User> userList = new ArrayList<User>();

		User user = new User();
		user.setUserId(0L);
		user.setUserName("test0");

		User user2 = new User();
		user2.setUserId(1L);
		user2.setUserName("test1");
		
		userList.add(user);
		userList.add(user2);
		
		//Legen Sie eine Liste der Benutzer im Formular fest und fügen Sie sie dem Modell hinzu, um die Grundlage für die Überprüfung zu legen, ob sie erfolgreich zum Modell hinzugefügt wurde.
		DbForm form = new DbForm();
		form.setUserList(userList);
		
		model.addAttribute("message", "hello!");// 1
		
		model.addAttribute("user", user);// 2
		
		model.addAttribute("dbForm", form);// 3
		
		return "hello";
	}

}

Im Folgenden folgen wir jedem Muster für model.addAttribute.

① Wurde der String im Modell gespeichert?

Beginnen wir mit einem einfachen Beispiel.

In model.addAttribute (" message "," hello! "); Speichert das Modell einfach "message" als Schlüssel und "hello" als Wert.

Der Testcode, um dies zu überprüfen, lautet wie folgt.

HelloControllerTest.java(Auszug)


@Test
Hallo wird im void init-Prozess an die Modellnachricht übergeben() throws Exception {
		this.mockMvc.perform(get("/hello/init"))
			.andExpect(model().attribute("message", "hello!"));
	}

Der Testcode ist auch sehr einfach, und wie Sie aus dem Teil `andExpect (model (). Attribute (" message "," hello! "))" Ersehen können, ist es fast dasselbe wie das Einfügen in das eigentliche Modell. Sie können auch Testcode schreiben.

image.png

Wenn Sie sich das Ergebnis tatsächlich ansehen, können Sie sehen, dass das Modellteil korrekt mit Werten gepackt ist.

Wenn es sich um ein einfaches Objekt handelt, kann es einfach geschrieben werden, da die Eigenschaft nur eine Ebene hat. Wenn Sie sich die Ergebnisse jedoch genauer ansehen, werden Sie feststellen, dass der Wert in eine zweifelhafte Zeichenfolge geschrieben ist. Es repräsentiert die Instanz des Objekts selbst. Natürlich gibt es Zeiten, in denen Sie überprüfen möchten, ob ein Objekt nicht null ist, aber meistens möchten Sie wissen, ob eine bestimmte Eigenschaft im Objekt den erwarteten Wert hat.

Im Folgenden wird die Validierung eines Modells mit diesen verschachtelten Eigenschaften beschrieben.

(2) Ist der Wert der userName-Eigenschaft der Benutzerentität wie erwartet in das Modell gepackt?

Das Überprüfen verschachtelter Objekte macht den Testcode etwas komplizierter, ist jedoch viel einfacher als das Interpretieren von Anmerkungen. Lassen Sie uns also jedes einzelne untersuchen.

Überprüfen Sie hier in Bezug auf die Verarbeitung von model.addAttribute (" user ", user);, ob die Eigenschaft "userName" der "user" -Instanz wie erwartet ist (hier der Wert "test0"). Gehen.

Beginnen wir mit dem eigentlichen Testcode.

HelloControllerTest.java(Auszug)


@Test
Die Benutzerentität wird durch ungültige Init-Verarbeitung im Modell gespeichert() throws Exception {
		this.mockMvc.perform(get("/hello/init"))
			.andExpect(model()
					.attribute("user", hasProperty(
										"userName", is("test0")
										)
							)
					);
	}

Plötzlich änderte sich die Struktur drastisch. Dies ist nicht der Testcode von Spring Boot, sondern die Verarbeitung durch das Framework, das den sogenannten "Matcher" verarbeitet, der die Gültigkeit des Tests mit dem Namen "Hamcrest" überprüft.

Die Methode hasProperty zum Überprüfen der Eigenschaften eines Objekts wird beim statischen Import verwendet, daher lautet die Struktur genau HasPropertyWithValue.hasProperty.

Und diese Methode hat die folgenden Rollen. (Zitiert vom Beamten)

Creates a matcher that matches when the examined object has a JavaBean property with the specified name whose value satisfies the specified matcher.

Irgendwie kam ein esoterischer englischer Satz heraus, aber ich denke, dass es gut kommen wird, wenn Sie sich ein aktuelles Beispiel ansehen. assertThat(myBean, hasProperty("foo", equalTo("bar")) Dies bedeutet, dass das Objekt "myBean" eine Eigenschaft namens "foo" hat und der Wert der foo-Eigenschaft "bar" ist. Genau das möchten wir in diesem Test überprüfen. Ein einfaches Beispiel für dieses Beispiel wäre assertThat (user, hasProperty (" userName ", is (" test0 "));. Da der Rückgabewert von hasProperty zum Matcher-Typ gehört, können Sie auch verschachtelte Eigenschaften schreiben.

Die Überprüfung verschachtelter Eigenschaften verlängert zwangsläufig den Code und macht es schwierig, die Entsprechung zwischen Klammern zu verstehen. Daher denke ich, dass einige Maßnahmen erforderlich sind, um das Lesen zu erleichtern, z. B. das Entwickeln von Einrückungen wie im obigen Beispiel.

Auf diese Weise können komplizierte Modelle gehandhabt werden. Schauen wir uns als Beispiel für das endgültige Modell den Testcode für das List-Objekt an.

Ergänzung: Was ist Matcher? Matcher ist selbstverständlich herausgekommen, aber wenn Sie JUnit nicht berührt haben, sind Sie möglicherweise nicht damit vertraut, daher werde ich es als Ergänzung kurz ansprechen. Matcher selbst ist eine Schnittstelle, die den Validierungsprozess in einem Test (gleich oder ungleich, alle Bedingungen ...) in einem einfachen und leicht lesbaren Format beschreibt.
Beispielsweise wird die häufig verwendete "assertThat" -Methode in der Form "assertThat (1 + 1, is (2))" geschrieben. Dies dient zum Schreiben des Testcodes in einem leicht lesbaren Format in Englisch, ähnlich dem oben beschriebenen Ausführungsprozess. Und was Sie im zweiten Argument der assertThat-Methode angeben, steht für "Matcher". Wenn Sie tatsächlich dem Inhalt der assertThat-Methode folgen, `if (! Matcher.matches (actual)) {Verarbeitung, wenn keine Übereinstimmung vorliegt}` Hier wird die Matches-Methode der im zweiten Argument angegebenen Matcher-Typ-Instanz aufgerufen. Da dieses Ergebnis ein Boolescher Wert ist, halte ich es für eine gute Idee, Mathcer grob als einen Booleschen Wert zum Speichern des Erfolgs oder Misserfolgs der Überprüfung zu interpretieren.
Selbst wenn es sich um eine verschachtelte Eigenschaft handelt, wird am Ende nur überprüft, ob der spezifische Eigenschaftswert in der unteren Ebene dem erwarteten Wert entspricht. Daher kann es überraschend klar sein, wenn Sie einfach denken und nicht zu gut vorbereitet sind. ..

Referenz

③ Enthält die in Model gepackte Liste die erwarteten Eigenschaften?

Schauen wir uns das endgültige Modellmuster an, das verschachtelt ist und eine Listenstruktur hat. Stellen Sie als allgemeines Beispiel für "model.addAttribute (" dbForm ", Formular);" sicher, dass die "Liste der Benutzer im Formularobjekt" Ihren Erwartungen entspricht. Schreiben Sie als Beispiel zuerst den folgenden Code.

HelloControllerTest.java(Auszug)



	//Greifen Sie bei Listenelementen mit hasItem in beliebiger Reihenfolge auf die Liste zu und überprüfen Sie, ob es ein Element gibt, dessen angegebene Eigenschaft den angegebenen Wert hat.
	//Machen Sie den Test nur grün, wenn er existiert
	@Test
Die Benutzerliste wird in der Modellform durch ungültige Init-Verarbeitung gespeichert() throws Exception {
		
		this.mockMvc.perform(get("/hello/init"))
			.andExpect(model().attribute("dbForm", hasProperty(
					"userList", hasItem(
						hasProperty(
								"userName", is("test1")
						)
					)
			)));
	}

Eine neue Methode namens "hasItem" ist erschienen. Offiziell Es wird gesagt, dass es nur für Objekte im Listenformat verwendet werden kann. Ich bin. Und die hier verwendete Methode hat Matcher als Argument.

Mit anderen Worten, grob gesagt, überprüfen wir, ob es mindestens einen gibt, der den Matcher erfüllt, der als Argument in der Liste übergeben wurde, die von der hasItem-Methode ausgeführt werden soll. In diesem Beispiel möchten wir überprüfen, ob für jedes Benutzerelement in der Benutzerliste mindestens eines vorhanden ist, dessen Eigenschaft "userName" auf "test1" festgelegt ist.

Da die Liste im Beispiel eine kleine Anzahl von Elementen wie "2" enthält, ist es möglich, den gesamten Inhalt zu untersuchen. In der tatsächlichen Anwendung wird jedoch häufig eine Liste mit Hunderten oder Tausenden von Elementen übergeben. .. Es ist schwer, dies alles zu überprüfen, obwohl es codiert werden kann. In einem solchen Fall scheint die Zuverlässigkeit in gewissem Maße gewährleistet zu sein, wenn überprüft werden kann, ob die Elemente am Anfang, in der Mitte und am Ende den Spezifikationen entsprechen. Anstatt alle Elemente der Liste zu überprüfen, müssen daher nur einige als repräsentative Elemente überprüft werden. Ich denke, es wäre besser, einige Testfälle mit der hasItem-Methode bereitzustellen.


Übrigens ist es ziemlich lang geworden, weil es mit verschiedenen ergänzenden Erklärungen gemischt wurde, aber dies vervollständigt die Überprüfung des Testcodes der Stufe 1. Wenn Sie Level 1 abgeschlossen haben, können Sie Folgendes tun:

Als nächstes möchte ich auf Ebene 2 die Überprüfung der Datenbank betrachten, die den Kern der Anwendung bildet.

Level2. Testen Sie Datenbankoperationen

Im Komponententest mit Spring Boot wird die Datenbank mit "DbUnit" überprüft. Wenn Sie es so schreiben, obwohl Spring Boot alleine voll ist, müssen Sie mehr lernen ... aber ich denke, es reicht aus, um zu lernen, wie man DbUnit einfach benutzt. Das Wichtigste ist, sich darüber im Klaren zu sein, "welche Art von Arbeit einfacher sein wird", indem DbUnit und Spring Boot kombiniert werden.

Wenn Sie plötzlich in einem Durcheinander über DbUnit schreiben, ist das Bild schwer zu verstehen. Lassen Sie uns zunächst den Ablauf verfolgen, wie Datenbankoperationen von manuellen Tests zu automatisierten Tests ersetzt werden.

Manueller Test

Betrachten Sie zunächst das manuelle Testen Ihrer Datenbankoperationen. Ich denke, dass der Test im folgenden Ablauf fortgesetzt wird.

Die Vor- und Nachteile des manuellen Testens bleiben hier, aber hier konzentrieren wir uns auf die "Testreproduzierbarkeit". Wenn Sie sich als Team entwickeln, ändert sich das Ergebnis von SELECT von Moment zu Moment, und die Verarbeitung von UPDATE und DELETE erfordert einige Vorbereitungen, wenn Sie dieselben Bedingungen erfüllen möchten. Wenn die durchgeführten Tests nicht reproduzierbar sind, ist es schwierig festzustellen, ob tatsächlich eine Verschlechterung aufgetreten ist, wenn wiederholte Tests wie Refactoring- und Regressionstests durchgeführt werden.

Lassen Sie uns nun etwas mehr über manuelle Tests entwickeln.

Manuelle Konstruktion des Testzustands

Um die Reproduzierbarkeit zu gewährleisten, habe ich versucht, den folgenden Prozess in den obigen manuellen Test einzubeziehen.

Dies stellte die Reproduzierbarkeit des Tests sicher. Wenn dies der Fall ist, können Sie mit Vertrauen testen ... !! Es ist möglicherweise nicht möglich, wenn es sich um eine kleine Anwendung handelt. Bei jeder kleinen Überprüfung können Sie jedoch die gesamte Datenbank sichern, die gesamte Datenbank löschen, die gesamte Datenbank wiederherstellen usw. Es wird sehr viel Zeit in Anspruch nehmen.

Selbst wenn Sie einen reproduzierbaren Teststatus erstellen und der Test selbst lange dauert oder das Ergebnis zurückgibt, wird der Test nicht zum richtigen Zeitpunkt ausgeführt. Ich wollte nur ein bisschen debuggen, aber wenn ich nicht gut genug wäre, müsste ich zehn Minuten warten, bevor die Ergebnisse zurückkommen, und wenn ich nicht gut genug wäre, würde es verschoben und ich würde zum manuellen Tick-Test zurückkehren.


Bisher scheint es eine entmutigende Aufgabe zu sein, Datenbankoperationen zu testen und gleichzeitig die Reproduzierbarkeit sicherzustellen. Durch Kombinieren von Spring Boot und DbUnit können Sie den obigen Test jedoch per Knopfdruck ausführen, obwohl einige Vorbereitungen erforderlich sind.

Schauen wir uns nun den Testcode mit Spring Boot und DbUnit als Hauptthema von Level 2 an.

Zu überprüfender Code

Schauen wir uns zunächst den Prozess an, bei dem das Ergebnis mit der königlichen Straße SELECT erzielt wird. Der Code der zu verifizierenden Dao-Schicht wird unten beschrieben.

UserDao.java(Auszug)


     /**
	 *Holen Sie sich alle Benutzerdatensätze aus der Datenbank
	 *Diesmal wurde der Prozess zum Testen vereinfacht.
	 * @return Liste der Benutzerentitäten
	 */
	public List<User> findAllUser() {
		
		QueryBuilder query = new QueryBuilder();
		
		query.append("select user_id, user_name from tm_user");
		
		return findResultList(query.createQuery(User.class, getEm()));
	}

Es werden verschiedene Prozesse geschrieben, aber die folgenden zwei Punkte sollten beachtet werden.

Das Auswählen von Datensätzen aus der Datenbank wird weiterhin wiederholt. Der erste Schritt besteht darin, die Anzahl der Datensätze in der Datenbank = Listengröße zu überprüfen.

Ich werde DbUnit sofort zur Überprüfung verwenden, aber einige Vorbereitungen sind erforderlich, bevor der eigentliche Testcode geschrieben wird. Es gibt eine Menge Dinge zu tun, um sich vorzubereiten, aber sobald Sie es beherrschen, können Sie es zu einer Routine für nachfolgende Datenbankbetriebstests machen, daher möchte ich genauer hinsehen.

Ich möchte Daten mit CSV verwalten

Zunächst legen wir den Grundstein für die Verwaltung von Datenbankeinträgen in Dateien. Als Standardfunktion von DbUnit werden Datensatztransaktionseinstellungen usw. in einer XML-Datei beschrieben. Dieses Mal werden jedoch Datensätze mit CSV verwaltet. Es gibt verschiedene Gründe, aber zusammenfassend ist die große Sache, dass Sie einfach schreiben können.

Ich werde im Folgenden einige Schritte ausführen, aber alle sind einfach, sodass Sie sie meiner Meinung nach bis zu einem gewissen Grad intuitiv verstehen können, ohne zu weit in DbUnit selbst zu gehen.

Zunächst erstellen wir eine Klasse, um die CSV-Datei zum Testen zu verwenden.

CsvDataSetLoader

CsvDataSetLoader.class


public class CsvDataSetLoader extends AbstractDataSetLoader{
	
	@Override
	protected IDataSet createDataSet(Resource resource) throws Exception {
		return new CsvURLDataSet(resource.getURL());
	}
}

Das Folgende ist eine ergänzende Erklärung der wichtigen Elemente.

Wörtlich eine abstrakte Klasse zum Lesen eines Datensatzes. Der Datensatz steht hier für "eine Reihe von Tabellen". Da diese abstrakte Klasse eine Implementierungsklasse der DataSetLoader-Schnittstelle ist, ist die zu erstellende Klasse vom Typ "DataSetLoader". Mit anderen Worten, wenn Sie sich die auf Klassenebene erstellte Klasse ansehen, ist dies so einfach wie die Beschreibung der Informationen "Dies ist eine Klasse zum Lesen eines Datensatzes".

Wie der Name schon sagt, handelt es sich um eine Factory-Methode zum Erstellen von Datasets. Das als Argument übergebene Objekt vom Ressourcentyp "resouce" enthält Informationen und Verhalten für den Zugriff auf die "echte Datei". Im eigentlichen Test hat das Ressourcenobjekt die Form, den Pfad der zu verarbeitenden CSV-Datei zu speichern.

In Official Diese Klasse erstellt ein IDataSet mit einer Basis-URL, die CSV-Dateien enthält Wie Sie sehen können, kann DbUnit die eigentliche CSV-Datei verarbeiten, indem sie sie auf der Grundlage des oben genannten Ressourcenobjekts abruft und in ein Dataset-Objekt konvertiert.

Einige Verarbeitungen wurden geschrieben, aber wie der Klassenname andeutet, dient diese Klasse zum Lesen der eigentlichen CSV-Datei und zum Bereitstellen zum Testen von Datenbankoperationen.

Einmal geschrieben, kann es beim Testen von Datenbankvorgängen mit CSV-Dateien in anderen Apps verwendet werden. Wenn Sie hier also einen Überblick über die einzelnen Prozesse erhalten, liegt das Problem darin. Ich denke nicht.


Nachdem die Klasse zum Lesen von CSV abgeschlossen wurde, erstellen wir eine CSV-Datei, die tatsächlich gelesen werden soll. Eine Beispieldatei finden Sie unter GitHub.

Es gibt verschiedene Möglichkeiten, die CSV-Datei selbst zu erstellen. Ich persönlich empfehle jedoch, DBeaver zu verwenden, um die CSV-Datei aus dem Datensatz zu extrahieren, da sie unverändert verwendet werden kann. Beachten Sie beim Erstellen einer CSV-Datei die folgenden Punkte.

Sie müssen auch vorsichtig sein, wo Sie Ihre CSV-Dateien ablegen. (Ich habe es an einen seltsamen Ort gebracht und war süchtig.) Grundsätzlich wird es unter "src / test / resources" platziert. Referenz

Die spezifische Datei- / Ordnerstruktur ist wie folgt.

image.png

Sie können sehen, dass es eine CSV-Datei gibt, die wie ein Tabellenname unter "src / test / resources / testData" aussieht. Und daneben befindet sich eine unbekannte Textdatei namens "table-ordering.txt". Dies dient dazu, externe Schlüsselbeschränkungen zu vermeiden, und gibt die Reihenfolge an, in der die Datenbanktabellen gelesen werden. Die spezifische Schreibmethode ist wie folgt.

table-ordering.txt


TableA
TableB
TableC

Testcode

Jetzt, da wir endlich fertig sind, können wir in den Testcode einsteigen. Die Anzahl der Anmerkungen wird plötzlich zunehmen, aber wenn Sie dies überwinden, wird sich der Bereich, in dem Sie Tests schreiben können, dramatisch erweitern, sodass ich mein Bestes geben werde.

DBSelectTest.java


@DbUnitConfiguration(dataSetLoader = CsvDataSetLoader.class)
@TestExecutionListeners({
	  DependencyInjectionTestExecutionListener.class,
	  TransactionalTestExecutionListener.class,
	  DbUnitTestExecutionListener.class
	})
@SpringBootTest(classes = {DaoTestApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class DBSelectTest {
	
	@Autowired
	private UserDao userDao;
	
	//Durch Setzen des Werts von DatabaseSetup auf den Pfad der CSV-Datei "table"-ordering.Siehe txt "
	//Erstellen Sie eine Testtabellengruppe, indem Sie eine sequentielle Tabelle erstellen
	//Zu diesem Zeitpunkt lautet der Wertpfad "src"./test/Ausgehend von "Ressourcen" lautet der Dateiname der CSV-Datei
	//Entspricht dem Namen der Tabelle
	//
	//Ebenfalls,@Durch Hinzufügen der Transaktionsanmerkung können Sie die Transaktion nach Abschluss des Tests zurücksetzen.
	//Kann getestet werden, ohne die Umwelt zu verschmutzen
	@Test
	@DatabaseSetup(value = "/testData/")
	@Transactional
	public void contextLoads() throws Exception {
		List<User> userList = userDao.findAllUser();
		
		//Hat Dao erfolgreich Datensätze aus der Tabelle abgerufen?
		assertThat(userList.size(), is(2));
	}

}

Klassenanmerkung

Beginnen wir mit den Anmerkungen, die der Klasse gegeben wurden, um einen Überblick zu erhalten.

DbUnitConfiguration

Wie Sie lesen können, handelt es sich um eine Anmerkung zum Festlegen verschiedener Einstellungen von DbUnit. Durch Angabe des oben in der Eigenschaft "dataSetLoader" erstellten "CsvDataSetLoader" kann die CSV-Datei gelesen werden. Es scheint, dass es verschiedene andere Einstellungen gibt, aber in diesem Stadium denke ich, dass es kein Problem gibt, zu erkennen, dass es zum Laden von CSV verwendet wird.

TestExecutionListeners

Dies ist der schwierigste Teil dieses Testcodes. Ich denke, diese Anmerkung sollte ausreichen, um Ihnen einen Überblick zu geben und zu organisieren, was an die Immobilie weitergegeben werden soll. Als Übersicht dient es zum Laden des erforderlichen TestExecutionListener, der die vor und nach der Ausführung des Testcodes auszuführende Verarbeitung definiert.

Die Beschreibung jedes Listeners ist grob in Official zusammengefasst. Hier werde ich kurz diejenigen beschreiben, die oft verwendet werden.

Geben Sie bei Verwendung von DI im Testcode an. Durch Angabe ist es möglich, die Testzielklasse mit Autowired usw. aus dem DI-Container zu injizieren.

Geben Sie an, wann Sie die Transaktion für den DB-Vorgang festlegen. Nach dem Betrieb der Datenbank ist es grundlegend, die Datenbank in ihren ursprünglichen Zustand zurückzusetzen. Daher ist sie für Tests, die die Datenbank verarbeiten, grundsätzlich unerlässlich.

Geben Sie an, wann Sie den Status der Datenbank vor und nach dem Test mit der später beschriebenen Anmerkung festlegen möchten. Wie der Name schon sagt, fügen Sie DbUnit bei Verwendung grundsätzlich hinzu.

Ergänzung: DirtiesContext und Listener-Standardeinstellungen Ich habe es hier nicht vorgestellt, aber Sie werden oft einen Listener namens "DirtiesContextTestExecutionListener" sehen. Es hat die Rolle eines Handlers für den DirtiesContext. DirtiesContext dient zum Ungültigmachen des Cache des Kontexts, der zum Ausführen des Testcodes verwendet wird.
Wenn Sie DirtiesContext aktivieren, dauert die Ausführung des Testcodes lange, da der Kontext nicht testweise zwischengespeichert wird. Es scheint verwendet zu werden, wenn der Testcode den Kontext ändert und nachfolgende Tests beeinflusst, aber es ist unwahrscheinlich, dass es auf der Basisebene verwendet wird, sodass Sie sich darüber keine Sorgen machen müssen. Wenn Sie es nicht verwenden möchten, müssen Sie natürlich klarstellen, warum Sie es nicht verwenden. Ich denke, es ist besser, das Konzept niedrig zu halten. [Referenz](https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-ctx-management-caching)
Als nächstes ändert sich die Geschichte und ist eine Ergänzung zu den Standardeinstellungen des Hörers. Auf den ersten Blick dachte ich, dass einige standardmäßig aktiviert sind und ich sollte nur das übergeben, was ich hinzufügen wollte. Es ist jedoch nicht wirklich aktiviert, und wenn ich den Beamten lese, der sich fragt, was das ist ..., scheint die Standardeinstellung nur gültig zu sein, wenn sie nicht in der "TestExecutionListeners-Annotation" angegeben ist. Das hier gezeigte Beispiel wurde angegeben, um den Listener für DbUnit zu aktivieren. In diesem Fall funktioniert es jedoch nicht, selbst wenn es in der Standardeinstellung geschrieben ist, es sei denn, Sie übergeben das, was Sie benötigen. .. [Referenz](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/TestContextBootstrapper.html#getTestExecutionListeners--)

SpringBootTest

Nun, dies ist der zweite Auftritt. Hier wird eine neue Eigenschaft "webEnvironment" übergeben. "MOCK" ist als Standardwert festgelegt, und es scheint, dass Sie eine sogenannte "Mock-Servlet-Umgebung" erstellen. Die Details wurden nicht viel offiziell geschrieben, aber was die Konsolenausgabe betrifft, scheint sie den Prozess der Generierung des DispatcherServlet für Tests darzustellen, die von MockMvc verwendet werden.

Da es nicht erforderlich ist, Anforderungen und Antworten nur mit dem Server in der Dao-Schicht auszutauschen, setzen Sie "NONE" als Eigenschaftswert. Dies verkürzt den Prozess der Erstellung eines Kontexts für MockMvc, wodurch der Test etwas schneller beendet wird.

Und obwohl die Reihenfolge umgekehrt wurde, hat sich auch geändert, was an die class-Eigenschaft übergeben wird. Dies bedeutet nicht, dass sich der Prozess erheblich geändert hat, sondern schränkt lediglich den Umfang der Komponentenscans ein. Wenn Sie sich den tatsächlichen Code ansehen, wird er zu Ihnen kommen.

DaoTestApplication.java


@EntityScan("app.db.entity")
@SpringBootApplication(scanBasePackages = "app.db.dao")
public class DaoTestApplication {

	public static void main(String[] args) {
		SpringApplication.run(DaoTestApplication.class, args);
	}

}

Das zu lesende Ziel ist auf "Dao-Ebene" und "Von Dao behandelte Entität" beschränkt. Mit zunehmender Größe der App steigt auch die Zeit, die zum Laden des Pakets benötigt wird, wodurch es zeitaufwändiger wird. Da die Verarbeitung in Bezug auf Datenbankoperationen häufig geändert wird und wir den Testcode ständig ausführen möchten, haben wir den Lesebereich minimiert, um die Zeit so weit wie möglich zu verkürzen.

Mit dieser Art von Einfallsreichtum wird der Test nach dem Dehnen in etwa einer Umdrehung des Halses abgeschlossen. Wenn Sie mehr Geschwindigkeit wünschen, müssen Sie mit der Config-Klasse und mit EntityManager herumspielen, aber das Testen ist nicht so tödlich langsam. Gehen Sie also nicht so weit.

Die oben genannten Einstellungen können schnell vorgenommen werden, und der Effekt kann so wie er ist erzielt werden. Ich denke, dass dies in der Grundphase ausreicht.


Methodenanmerkung

Es geht wieder um Anmerkungen, aber es ist einfacher als Anmerkungen auf Klassenebene, daher denke ich, dass es Ihnen in den Sinn kommen wird.

DatabaseSetup

Dies ist eine Anmerkung, die den "Anfangszustand" der Datenbank definiert. Wenn Sie das Verzeichnis angeben, in dem sich die CSV-Datei in der value-Eigenschaft befindet, werden die Werte basierend auf der CSV-Datei in die Datenbanktabelle gepackt. Sie können auch verschiedene Status erstellen, indem Sie die Verzeichnisse wechseln.

Auf diese Weise können Sie den Status der Tabelle immer neu erstellen, wenn Sie den Test starten möchten, ohne manuell in die Tabelle einfügen zu müssen. Vielen Dank.

Transactional

Es ist eine vertraute, die häufig in der tatsächlichen Anwendungsentwicklung verwendet wird. Normalerweise verhält sich eine Methode mit dieser Annotation wie ein Commit, wenn sie normal funktioniert, ein Rollback, wenn etwas Unerwartetes ausgeführt wird, und so weiter. Im Fall von Testcode geht jedoch die Reproduzierbarkeit des Tests verloren, wenn die Datenbank nach jedem Test neu geschrieben wird. Daher wird sie standardmäßig bei jeder Ausführung der Methode zurückgesetzt.
Durch Kombinieren der beiden oben genannten Anmerkungen können Sie die Datenbank manuell sichern, Datensätze aus Dateien einfügen, am Ende wieder einfügen usw.

Wenn Sie den Test tatsächlich ausführen, können Sie die Liste der Benutzerentitäten mit der Dao-Methode abrufen und überprüfen, ob Sie das erwartete Ergebnis erhalten (Listengröße = Anzahl der Datensätze).


Durch die Überprüfung des SELECT-Prozesses haben wir die Grundlagen des Testcodes für Datenbankoperationen in gewissem Umfang behandelt, sodass ich mir andere Prozesse gleichzeitig ansehen möchte.

Ergänzung: Wo soll der EntityManager eingestellt werden? Es ist ein bisschen anders als der Test selbst, aber meiner persönlichen Erfahrung nach war der EntityManager oft null und der Test hat nicht funktioniert. Mir war bewusst, dass wenn ich EntityManager im Feld der Dao-Klasse deklarierte und die Annotation "PersistenceContext" hinzufügte, dies vorerst funktionieren würde, sodass ich es nicht lösen konnte und süchtig danach war.
Die eigentliche Bewegung besteht darin, dass eine Bean namens "LocalContainerEntityManagerFactoryBean" die EntityManagerFactory initialisiert und einen EntityManager von DI erstellt. Zu diesem Zeitpunkt ist ein DI-Container erforderlich, aber im Frühjahr scheint ApplicationContext diese Rolle zu spielen.
Da es wie oben funktioniert, funktioniert es vorerst, auch wenn Sie EntityManager mit Autowired- oder PersistenceContext-Annotation in der Testklasse erhalten und an die Testzielklasse übergeben. Dies würde jedoch den tatsächlichen Vorgang in der App von dem Vorgang im Testcode unterscheiden. Ich persönlich denke, dass es besser ist, ihn in der folgenden Form zu verwenden.
- Erstellen Sie eine Dao-Basisklasse und legen Sie EntityManager im Feld Basisklasse fest. (Fügen Sie zu diesem Zeitpunkt die PersistenceContext-Annotation hinzu.) -In der Basisklasse wird nur der Getter von EntityManager verfügbar gemacht, und in der abgeleiteten Klasse ist nur der Getter eingeschränkt. - Grundlegende Methoden mit EntityManager (Zusammenführen, Beibehalten usw.) werden auf der Seite der Basisklasse definiert. Es gibt nicht viele Informationen über EntityManager, und ich war süchtig danach, es schlecht zu schreiben. Ich denke, es ist besser, es zunächst Spring zu überlassen. Wenn es im Testcode stecken bleibt und die Implementierung überhaupt nicht fortgesetzt wird, ist es möglicherweise nicht gut für die psychische Gesundheit, daher werde ich es als Memorandum schreiben. [Referenz](https://builder.japan.zdnet.com/sp_oracle/35067018/)
* Wenn Sie Repository verwenden, ist EntityManager vollständig ausgeblendet, sodass Sie sich dessen wahrscheinlich nicht bewusst sein müssen.
[Dao-Basisklasse](https://github.com/a-pompom/SpringBoot-MVC-Test/blob/master/dbMVCTest/src/main/java/app/db/dao/BaseDao.java) [Von Dao abgeleitete Klasse](https://github.com/a-pompom/SpringBoot-MVC-Test/blob/master/dbMVCTest/src/main/java/app/db/dao/UserDao.java)

Testen Sie die CRUD-Verarbeitung der Datenbank

Bei der CRUD-Verarbeitung konnten wir SELECT überprüfen. Schauen wir uns also die verbleibende Aktualisierungs- / Erstellungsverarbeitung an. Ich denke, dass Sie die Gliederung mit dem Wissen verstehen können, das Sie bisher erworben haben, so dass der tatsächliche Testcode unten beschrieben wird.

CRUDDaoTest.java(Auszug)


//Verarbeitung, um den Status nach Ausführung der Testmethode in der Datenbank wiederzugeben
	//Normalerweise wird die Aktualisierungsverarbeitung mit der Datenbank synchronisiert, wenn die Transaktion festgeschrieben wird.
	//Explizite Synchronisierung, da im Testprozess keine Festschreibung erfolgt
	@AfterEach
	void tearDown() {
		userDao.getEm().flush();
	}
	
	/**
	 *Überprüfen Sie, ob beim Erstellen ein neuer Datensatz erstellt wird
	 *Stellen Sie sicher, dass die Datenbank wie von der Entität erwartet neu geschrieben wurde, indem Sie sie mit der erwarteten Datenbank vergleichen
	 */
	@Test
	@DatabaseSetup(value = "/CRUD/setUp/forCreate")
	@ExpectedDatabase(value = "/CRUD/create/", assertionMode=DatabaseAssertionMode.NON_STRICT)
Mit der Methode void create wird ein neuer Benutzer erstellt() {
		User user = new User();
		user.setUserName("test3");
		
		userDao.saveOrUpdate(user);
	}
	
	/**
	 *Überprüfen Sie, ob der vorhandene Datensatz durch den Aktualisierungsprozess aktualisiert wird
	 *Stellen Sie sicher, dass die Datenbank wie von der Entität erwartet neu geschrieben wurde, indem Sie sie mit der erwarteten Datenbank vergleichen
	 */
	@Test
	@DatabaseSetup(value = "/CRUD/setUp/")
	@ExpectedDatabase(value = "/CRUD/update/", assertionMode=DatabaseAssertionMode.NON_STRICT)
Benutzer 1 kann mit der Void-Update-Methode neu geschrieben werden() {
		User user = new User();
		user.setUserId(1L);
		user.setUserName("test1mod");
		
		userDao.saveOrUpdate(user);
	}
	
	/**
	 *Überprüfen Sie, ob der Datensatz durch den Löschvorgang gelöscht wird
	 *Bereiten Sie vor und nach der Verarbeitung eine Datenbank vor und überprüfen Sie die Gültigkeit, indem Sie vergleichen, ob das erwartete Ergebnis nach dem Löschen erzielt wird.
	 */
	@Test
	@DatabaseSetup(value = "/CRUD/setUp/")
	@ExpectedDatabase(value = "/CRUD/delete/", assertionMode=DatabaseAssertionMode.NON_STRICT)
Benutzer 1 kann mit der Methode void delete gelöscht werden() {
		userDao.delete(1);
	}

Nachdem wir einige neue haben, werfen wir einen kurzen Blick auf jeden einzelnen. Es gibt auch einige Einschränkungen hinsichtlich des Testcodes für die CURD-Verarbeitung von Datenbankoperationen. Schauen wir uns also auch diese an.

AfterEach

Dies ist eine Anmerkung für JUnit5 und beschreibt den Prozess, den Sie nach Ausführung jeder Testmethode einfügen möchten. Hier wird die Flush-Methode von EntityManager explizit aufgerufen. Die Flush-Methode erledigt die Arbeit, um die Entitäten im Persistenzkontext mit den Datensätzen in der Datenbank zu synchronisieren. Normalerweise wird diese Methode automatisch aufgerufen, wenn die Transaktion festgeschrieben wird, ohne dass sie sich dessen bewusst ist. Referenz

In diesem Testcode müssen Sie jedoch "RollBack" ausführen, um die Datenbank nach Abschluss des Datenbankvorgangs wiederherzustellen. Dann wird die Flush-Methode nicht aufgerufen, sodass das erwartete Ergebnis der Testmethode nicht in der Datenbank angezeigt wird und der Test nicht bestanden wird. Es gibt verschiedene Möglichkeiten, damit umzugehen, aber es scheint besser, die Flush-Methode explizit aufzurufen, wenn jede Methode eine Transaktion festschreibt, dh wenn der Prozess abgeschlossen ist, genau wie beim Ausführen einer App.

Durch Aufrufen der Flush-Methode nach Ausführung jeder Testmethode kann das erwartete Ergebnis korrekt überprüft werden.

ExpectedDatabase

Es wird gleichzeitig mit der Annotation DatabaseSetup verwendet und dient, wie der Name schon sagt, zur Überprüfung des Status der Datenbank nach Ausführung der Testmethode. Geben Sie wie bei der DatabaseSetup-Annotation das Verzeichnis an, in dem die CSV-Datei, die den Tabellenstatus des erwarteten Ergebnisses beschreibt, im Wert value gespeichert ist. Außerdem wird die Eigenschaft "assertionMode" festgelegt. Wenn Sie hier jedoch "NON_STRICT" festlegen, werden nur die in der CSV-Datei angegebenen Spalten überprüft, nicht alle Spalten.

Transaktionsanmerkung

In dieser Testklasse wird die "Transaktionsanmerkung" auf Klassenebene hinzugefügt. Das Festlegen dieser Annotation auf Klassenebene entspricht dem Hinzufügen einer Annotation zu allen Methoden in der Klasse. Einige Controller-Tests erfordern keine Transaktionssteuerung. Wenn Sie jedoch versuchen, jede Methode jedes Mal festzulegen, treten Auslassungen auf. Daher ist es besser, sie alle auf Klassenebene festzulegen.


Jetzt haben Sie ein Verständnis für die Verarbeitung, die für die CRUD-Verarbeitung erforderlich ist. Am Ende von Level 2 sind beim Testen von Datenbankoperationen einige Dinge zu beachten (weil ich süchtig danach bin). Ich hoffe es wird für Sie hilfreich sein.

Informationen zur Beschreibungsmethode des Aktualisierungs- / Löschvorgangs

Der obige Prozess ist ein Prozess zum Umschreiben eines vorhandenen Datensatzes. Ich denke, dass es mehrere Datensätze verarbeiten kann, aber in den meisten Fällen zielen Webanwendungen auf einen Datensatz. Zu diesem Zeitpunkt sind Schlüsselinformationen erforderlich, um das Verarbeitungsziel zu klären.

Ich denke, es gibt verschiedene Möglichkeiten, dies zu tun, aber ich denke, es ist einfach und leicht zu schreiben, "Geben Sie die ID im Datensatz der CSV-Datei an". Der hier zu beachtende Punkt ist das Konzept der Logik zur Durchführung des Tests. Da es etwas lang zu sein scheint, habe ich es in der Beilage geschrieben. Schauen Sie also bitte vorbei, wenn Sie interessiert sind.

Ergänzung: So implementieren Sie den Test Bereiten Sie im Hinblick auf die oben beschriebene Methode zum Erfassen von "Schlüsselinformationen" eine Dienstprogrammklasse zum Testen vor, um das Schreiben eines Tests zu vereinfachen, oder fügen Sie dem Code auf der Anwendungsseite eine Methode hinzu, um das Testen zu vereinfachen. Es gibt nichts, was Sie nicht tun können, aber es wird nicht empfohlen.
Wenn Sie beim Schreiben eines Tests zum Erstellen einer Utility-Klasse nicht weiterkommen, um das Schreiben zu vereinfachen, sollten Sie zunächst nicht darüber nachdenken, wie Sie den Test bestehen. Sie sollten darüber nachdenken, ob Sie es einfacher schreiben können. Wenn Sie eine Testmethodenklasse auf einer einfachen CRUD-Verarbeitungsebene schreiben, können Sie sich leicht vorstellen, wie Ihr Testcode in einer Anwendung auf Arbeitsebene aussehen würde.
Es wird auch oft gesagt, dass Code, der einfach zu schreiben ist, guter Code ist. Dies ist keine Geschichte, die geschrieben werden sollte, wenn man den Test auf der Anwendungsseite besteht, aber es sollte verhindert werden, dass "einzelne Module eng miteinander verbunden sind und es schwierig wird, Abhängigkeiten zum Zeitpunkt des Tests aufzulösen". Ding. Eine solche Implementierung ist nicht nur schwer zu testen, sondern erweitert auch den Wirkungsbereich beim Erweitern oder Ändern, was zur Entstehung unerwarteter Fehler führt.
Wenn Sie sich auf den Testcode konzentrieren, ist dieser näher am Testcode als an der Implementierung, und umgekehrt ist dieser Teil am Anfang schwer zu bemerken, aber es kann sinnvoll sein, eine Pause einzulegen und zu den Grundlagen zurückzukehren. nicht. Ich habe es so geschrieben, aber ich bin süchtig danach, den Testcode selbst zu schreiben, also schreibe ich ihn als Selbstdisziplin.

Informationen zum ID-Wert des Erstellungsprozesses

Betrachten Sie den Fall der Registrierung eines neuen Datensatzes in der Datenbank mit einer Testmethode. Wenn die ID beispielsweise automatisch nummeriert und dem Setup-Datensatz zugewiesen wird, kann es zu einer Schlüsselverdoppelung kommen.

Wenn Sie in diesem Fall die ID festlegen, dass der Datensatz der Ergebnismenge ebenfalls nummeriert ist, ist es sicherer, den automatisch nummerierten Wert nicht zu steuern.

Wenn Sie als Lösung die Generierung eines neuen Datensatzes überprüfen möchten, ist es meiner Meinung nach besser, mit der Richtlinie fortzufahren, eine CSV-Datei ohne die ID zu verwenden und nur die Inhaltsspalte ohne die betreffende ID zu überprüfen.


In Level 2 sind viele neue Dinge herausgekommen. Wenn Sie sich jedoch ein wenig daran gewöhnt haben, können Sie klar schreiben und vor allem den Server wie einen manuellen Test starten, auf die Seite zugreifen, sie tatsächlich verarbeiten und die Datenbank aufrufen ... Ich denke, dass es ein sehr nützlicher Teil ist, weil es überprüft werden kann, ohne es zu tun. Selbst wenn Sie den Bereich bis Stufe 2 beherrschen, wird die Effizienz der Fehlerkorrektur während der Entwicklung erheblich verbessert.

Wenn Sie Level 2 abgeschlossen haben, sollten Sie in der Lage sein:


Spring Boot ist übrigens ein Framework zum Erstellen von Webanwendungen. Daher werden häufig POST-Anforderungen verwendet, wenn die Datenbank tatsächlich betrieben wird. Daher möchten wir auf Ebene 3 einen Blick auf die Validierung von POST-Anforderungen werfen. Das Level steigt, aber es ist etwas, das Sie mit Ihrem Wissen bisher vollständig verstehen können. Ich würde mich freuen, wenn Sie mir bis zum Ende folgen könnten (╹◡╹)

Level3. POST-Anfrage testen

Schauen wir uns als nächstes den Testcode zur Validierung von POST-Anforderungen an. Da es lange dauern würde, den gesamten zu überprüfenden Code zu platzieren, möchte ich mich auf den Testcode konzentrieren, indem ich hier nur den Umriss der Anwendung beschreibe.

Auf Stufe 3 werden wir die TODO-Liste als Thema verwenden. Es ist einfach und kann die folgende einfache CRUD-Verarbeitung ausführen.

image.png

Es wird einige neue Kenntnisse über POST-Anfragen geben, aber es ist verständlich, wenn Sie über die bisherigen Kenntnisse verfügen. Schauen Sie sich daher nach einer umfassenden Überprüfung dieses Artikels den Testcode an. Der tatsächliche Testcode wird unten angezeigt. Es ist etwas länger, aber das meiste ist verständlich ... Ich bin glücklich.

TodoControllerTest.java


@DbUnitConfiguration(dataSetLoader = CsvDataSetLoader.class)
@TestExecutionListeners({
	  DependencyInjectionTestExecutionListener.class,
	  TransactionalTestExecutionListener.class,
	  DbUnitTestExecutionListener.class
	})
@AutoConfigureMockMvc
@SpringBootTest(classes = {DbMvcTestApplication.class})
@Transactional
public class TodoControllerTest {
	
	//mockMvc Mock-Objekt zur Verarbeitung von HTTP-Anforderungen und -Antworten ohne Bereitstellung auf dem Tomcat-Server
	@Autowired
	private MockMvc mockMvc;
	
	@Autowired
	private TodoDao todoDao;
	
	@AfterEach
	void tearDown() {
		todoDao.getEm().flush();
	}
	
	/**
	 *Stellen Sie sicher, dass die Ansicht korrekt zurückgegeben wird
	 * @throws Exception
	 */
	@Test
Todo wird als Ansicht in der ungültigen Init-Verarbeitung übergeben() throws Exception {
		this.mockMvc.perform(get("/todo/init"))
			.andExpect(status().isOk())
			.andExpect(view().name("todo"));
	}
	
	/**
	 *Stellen Sie sicher, dass der von DB erfasste Datensatz im Modell festgelegt ist
	 *Diesmal ist dies kein komplizierter Prozess. Wenn also ein Datensatz in der Datenbank an das Modell übergeben wird, wird davon ausgegangen, dass er normal funktioniert.
	 * 
	 * @throws Exception
	 */
	@Test
	@DatabaseSetup(value = "/TODO/setUp/")
Der void init-Prozess übergibt eine vorhandene Aufgabe an das Modell() throws Exception {
		
		//Mit mockMvc/todo/Senden Sie eine Get-Anfrage an "init"
		this.mockMvc.perform(get("/todo/init"))
		//DB-Datensätze werden als Liste an das Modell übergeben
			.andExpect(model().attribute("todoForm", hasProperty(
					"todoList", hasItem(
							hasProperty(
									"task", is("task1")
							)
					)
			)));
	}
	
	/**
	 *Überprüfen Sie anhand der Eingabe auf dem Bildschirm, ob neue Datensätze in der Datenbank registriert sind
	 * @throws Exception
	 */
	@Test
	@DatabaseSetup(value = "/TODO/setUp/create")
	@ExpectedDatabase(value = "/TODO/create/", assertionMode=DatabaseAssertionMode.NON_STRICT)
Eine neue Aufgabe wird durch ungültige Speicherverarbeitung in der Datenbank registriert() throws Exception {
		
		this.mockMvc.perform(post("/todo/save")
			.contentType(MediaType.APPLICATION_FORM_URLENCODED)
			.param("newTask", "newTask"));
		
	}
	
	/**
	 *Überprüfen Sie, ob vorhandene Datensätze durch Bildschirmeingabe aktualisiert werden
	 *Da diesmal keine Bildschirminformationen verwendet werden, ist es nicht möglich, die automatisch nummerierte ID zu erhalten.
	 *Geben Sie daher dieses Mal das Aktualisierungsziel manuell an.
	 *Grundsätzlich ist die Reihenfolge der Liste nicht garantiert, daher scheint es notwendig zu sein, sie zum Zeitpunkt von SELECT zu sortieren.
	 * @throws Exception
	 */
	@Test
	@DatabaseSetup(value = "/TODO/setUp/")
	@ExpectedDatabase(value = "/TODO/update/", assertionMode=DatabaseAssertionMode.NON_STRICT)
Der ungültige Aktualisierungsprozess aktualisiert die vorhandene Aufgabe() throws Exception{
		
		//"To do" mit mockMvc/Senden Sie eine Post-Anfrage an "Update"
		long updateTargetId = 3L;
		int updateTargetIndex = 2;
		
		this.mockMvc.perform(post("/todo/update/" + updateTargetIndex + "/" + updateTargetId)
				.param("todoList[" + updateTargetIndex + "].task", "task3mod")
				.contentType(MediaType.APPLICATION_FORM_URLENCODED)
				);
		
	}
	/**
	 *Überprüfen Sie, ob die auf dem Bildschirm ausgewählte Aufgabe gelöscht wurde
	 * @throws Exception
	 */
	@Test
	@DatabaseSetup(value = "/TODO/setUp/")
	@ExpectedDatabase(value = "/TODO/delete/", assertionMode=DatabaseAssertionMode.NON_STRICT)
Der Vorgang zum Löschen der Leere löscht die vorhandene Aufgabe() throws Exception {
		long deleteTargetId = 3L;
		
		this.mockMvc.perform(post("/todo/delete/" + deleteTargetId)
				.contentType(MediaType.APPLICATION_FORM_URLENCODED)
				);
		
	}
}

Im Folgenden werden die neu eingeführten Methoden und Punkte für POST-Anforderungen beschrieben, die bei der Bearbeitung von POST-Anforderungen zu beachten sind. Ich denke nicht, dass es beängstigend ist, weil Sie nur Parameter einstellen und Anfragen stellen.

POST-Parameter

Ein bemerkenswerter Punkt im POST-Anforderungstestcode ist das Festlegen der an die Anforderung übergebenen Parameter. Wenn Sie die POST-Anforderung jedoch bis zu einem gewissen Grad verstehen, können Sie sie intuitiv festlegen. Für POST-Anfragen empfehlen wir dies, da es eindeutig in MDN geschrieben ist.

Übrigens wird im Testcode mit "MockMvc" der Teil, in dem die GET-Anforderung von der perform-Methode auf Ebene 1 gestellt wurde, in die POST-Anforderung geändert. Danach können Sie mit der param-Methode Parameter im Schlüsselwertformat übergeben, sodass Sie einfach eine Anfrage gemäß dem in der tatsächlichen Anfrage übergebenen Formular stellen können. Sie können die param-Methode auch in einer GET-Anforderung aufrufen. In diesem Fall wird sie jedoch als Abfrageparameter gesendet. Hier wird die POST-Anforderung basierend auf dem Formular gesendet, sodass die Parameter im Anforderungshauptteil gespeichert werden.

Obwohl der contentType ohne Angabe funktioniert, ist es meiner Meinung nach besser, ihn so einzustellen, dass er der tatsächlichen POST-Anforderung so nahe wie möglich kommt.


Dinge, die beim Testen von POST-Anfragen zu beachten sind

Dieses Mal überprüfen wir hauptsächlich, ob die Datenbank durch die POST-Anforderung korrekt aktualisiert wurde. Zu diesem Zeitpunkt besteht das Problem darin, was von der POST-Anforderung verarbeitet wird. Ich möchte einen kurzen Blick auf jeden CRUD-Prozess werfen.

Wenn Sie einen neuen Datensatz erstellen, sind die Parameter für den neuen Datensatz unabhängig von der Tabelle, sodass Sie sich darüber keine Gedanken machen sollten.

Diesmal ist der Überprüfungsbereich so lange, bis der Ansichtsname an View übergeben wird. Daher ist es in Ordnung, wenn Sie das an Model übergebene Objekt überprüfen können. Auch hier gibt es also keinen Grund zur Sorge ...

Da die zu löschende ID durch den Pfad der Anforderung bestimmt wird, muss das Löschziel beim Erstellen einer Anforderung mit MockMvc eindeutig angegeben werden. Diese Konventionen sollten in der "Implementierung" vermieden werden, aber ich denke, Sie müssen sich im Testcode nicht zu viele Sorgen machen. Erstens definiert der Testcode den Status der Datenbank als "fest". Anstatt Änderungen und Erweiterungen anzunehmen, sollten Sie sich auf den Teil konzentrieren, "ob eine konstante Ausgabe immer von einer konstanten Eingabe erhalten wird". Die Stärke des Testcodes besteht darin, dass Sie immer das gleiche Ergebnis erzielen können, egal wie oft Sie es ausführen. Ich persönlich denke daher, dass Sie darüber nachdenken sollten, wie Sie es getrennt von der Implementierung schreiben können.

Gleiches gilt für den Update-Prozess. Wenn Sie jedoch beim Aktualisieren einen Datensatz in der Liste der Entitäten als Ziel festlegen möchten, müssen Sie einige Maßnahmen ergreifen, z. B. das Bearbeitungsziel von der Liste trennen und in einer separaten Aktualisierungsentität speichern. Bei diesem Aktualisierungsprozess ist die ID der Indexentität der Liste festgelegt, aber die Reihenfolge der Liste ist grundsätzlich nicht garantiert, sodass in der Anwendung auf Unternehmensebene in der obigen Form "immer" Es ist erforderlich, einen Zustand zu erstellen, in dem dasselbe Ergebnis mit derselben Eingabe erzielt werden kann. Ich möchte darüber schreiben, wenn ich mich an den Bildschirmtestcode (Wunsch) gewöhnt habe.


Obwohl es als Level 3 eingestuft wurde, war das meiste bisher in Form einer umfassenden Überprüfung, also verstehe ich ... ich verstehe ... !! Ich würde mich sehr freuen, wenn Sie könnten (:) Wenn Sie den Testcode der Stufe 3 verstehen, können Sie:


Zusammenfassung

Es war länger als ich erwartet hatte, aber jetzt kann ich sehen, wie man einen einfachen Testcode für die CRUD-Verarbeitung schreibt. Wenn Sie den Implementierungsteil schreiben, müssen Sie sich der Dinge bewusst sein, die Sie normalerweise nicht kennen, und ich denke, es gab einige schwierige Teile. Das Schreiben von Testcode vertieft jedoch Ihr Verständnis des Frameworks und der Sprache, rationalisiert die Entwicklung und bietet viele Vorteile.

Und das Beste ist, dass Sie die Freude am Bestehen eines Tests nicht allein mit der Implementierung genießen können. Wenn Sie die erste Barriere überwunden haben, macht das Schreiben von Testcode viel Spaß.

Durch diesen Artikel kann ich möglicherweise Testcode mit Spring Boot schreiben ...? Ich würde es begrüßen, wenn Sie denken könnten. Ich bin noch nicht ausgereift in Bezug auf den Testcode, daher würde ich gerne weitere Erklärungen zum Testcode sehen.

Recommended Posts

Schreiben Sie den Testcode mit Spring Boot
Schreiben wir einen Testcode für die Anmeldefunktion mit Spring Boot
Testen Sie den Controller mit Mock MVC im Spring Boot
Führen Sie ein Spring Boot-Projekt mit VS-Code aus
Legen Sie den Kontextparameter in Spring Boot fest
Spring Boot 2 Multiprojekt mit Gradle
Schreiben Sie Java8-ähnlichen Code in Java8
Wichtige Änderungen in Spring Boot 1.5
NoHttpResponseException in Spring Boot + WireMock
So schreiben Sie einen Komponententest für Spring Boot 2
[JUnit 5-kompatibel] Schreiben Sie einen Test mit JUnit 5 mit Spring Boot 2.2, 2.3
[JUnit 5] Schreiben Sie einen Validierungstest mit Spring Boot! [Parametrisierungstest]
Testen Sie die Klasse mit Feldinjektion im Spring-Boot-Test, ohne den Spring-Container zu verwenden
Frühlingsstiefel Hallo Welt in Eclipse
Spring Boot-Anwendungsentwicklung in Eclipse
Überprüfungspunkte für den Spring Boot-Anwendungscode
Java Spring-Umgebung in vs Code
Spring Boot Programmierung mit VS Code
Implementieren Sie die REST-API mit Spring Boot
Was ist @Autowired im Spring Boot?
Verwenden Sie DBUnit für den Spring Boot-Test
Implementieren Sie die Spring Boot-Anwendung in Gradle
Verwendung von Thymeleaf mit Spring Boot
Beispielcode, der die Moustache-Vorlagen-Engine mit Spring Boot verwendet
Beispielcode zum Testen eines Spring Boot-Controllers mit MockMvc
[Spring Boot] Bis @Autowired in der Testklasse [JUnit5] ausgeführt wird
Führen Sie RSpec ein und schreiben Sie den Unit-Test-Code
Starten Sie mit IntelliJ ein (altes) Spring Boot-Projekt
Erstellen Sie mit Gradle ein Spring Boot + Docker-Image
Statische Dateizugriffspriorität beim Spring Boot
Spring Boot-Protokoll im JSON-Format ausgeben
Memorandum zum Herunterladen lokaler Dateien mit Spring Boot
Führen Sie einen Transaktionsbestätigungstest mit Spring Boot durch
Versuchen Sie es mit Spring Boot mit VS-Code
Erstellen Sie mit IntelliJ ein Java Spring Boot-Projekt
Lösen Sie die Thymeleaf-Syntaxprüfung in Spring Boot
Der Spring Boot @ WebMvcTest-Test aktiviert die Standardsicherheit von Spring Security
[Trainieren! ] Zeigen Sie Hello World mit Spring Boot an
Verwenden Sie die DynamoDB-Abfragemethode mit Spring Boot
Antwortdaten direkt im Frühjahr schreiben
Schreiben Sie Code, der schwer zu testen ist
DI SessionScope Bean im Spring Boot 2-Filter
Formularklassenvalidierungstest mit Spring Boot
Ändern Sie das Sitzungszeitlimit in Spring Boot
Fordern Sie Spring Boot heraus
Spring Boot Form
Spring Boot Denken Sie daran
gae + frühlingsstiefel
SameSite-Cookie im Spring Boot (Spring Web MVC + Tomcat)
Informationen zum Entwerfen einer Spring Boot- und Unit-Test-Umgebung
Asynchrone Verarbeitung mit regelmäßiger Ausführung in Spring Boot
Anforderungs- und Antwortprotokolle mit Spring Boot ausgeben
JUnit 5: Wie man Testfälle in enum schreibt
Schreiben Sie schnell RestController-Tests mit Spring Boot + Spock
Servlet-Filter mit Spring Boot verwenden [Spring Boot 1.x, 2.x kompatibel]
So fügen Sie in Spring Boot einen Klassenpfad hinzu
Java-Tipps - Erstellen Sie mit Gradle ein Spring Boot-Projekt
So schreiben Sie Testcode mit Basic-Zertifizierung
So binden Sie mit einer Eigenschaftendatei in Spring Boot