Matteo Manferdini

Viele Entwickler finden Unit-Tests verwirrend. Dies wird noch verschlimmert durch die fortgeschrittenen Techniken, die man benötigt, um Klassen oder asynchronen Code zu testen, wie z.B. den für Netzwerkanfragen.

In Wirklichkeit liegen dem Unit-Testing einfache, grundlegende Konzepte zugrunde. Sobald man diese verstanden hat, wird Unit Testing plötzlich zugänglicher.

Inhalt

  • Unit-Testing erklärt in einfachen, verständlich erklärt
  • Mit Unit-Tests können Sie schwer zugängliche Randfälle überprüfen und Bugs verhindern
  • Schreiben von Unit-Tests in Xcode
  • Eine gute Architektur erleichtert das Testen Ihres Codes
  • Behandeln von Werttypen als reine Funktionen, um Unit-Tests zu vereinfachen
  • Überprüfen Sie Ihren Code mit den Assertions-Funktionen des XCTest-Frameworks
  • Messen Sie die Codeabdeckung eines Tests in Xcode
  • Warum es sinnlos ist, eine bestimmte Codeabdeckung anzustreben, und was Sie stattdessen tun sollten

Unit-Tests in einfachen, verständlichen Worten erklärt

Wenn Sie eine Anwendung schreiben, durchlaufen Sie einen Zyklus, in dem Sie Code schreiben, ihn ausführen und überprüfen, ob er wie vorgesehen funktioniert. Aber je größer der Code wird, desto schwieriger wird es, die gesamte Anwendung manuell zu testen.

Automatisierte Tests können diese Tests für Sie durchführen. Praktisch gesehen sind Unit-Tests also Code, mit dem Sie sicherstellen können, dass Ihr App-Code korrekt ist.

Der andere Grund, warum Unit-Tests schwer zu verstehen sein können, ist, dass sie von vielen Konzepten umgeben sind: Testen in Xcode, App-Architektur, Test-Doubles, Dependency Injection und so weiter.

Aber im Kern ist die Idee der Unit-Tests ziemlich einfach. Sie können einfache Unit-Tests in einfachem Swift schreiben. Sie brauchen keine spezielle Xcode-Funktion oder ausgefeilte Technik, und Sie können sie sogar in einem Swift Playground ausführen.

Schauen wir uns ein Beispiel an. Die folgende Funktion berechnet die Fakultät einer ganzen Zahl, die das Produkt aller positiven ganzen Zahlen kleiner oder gleich der Eingabe ist.

1
2
3
4
5
6
7

func factorial(of number: Int) -> Int {
var result = 1
for factor in 1…number {
result = result * factor
}
return result
}

Um diese Funktion manuell zu testen, füttert man sie mit ein paar Zahlen und überprüft, ob das Ergebnis den Erwartungen entspricht. Zum Beispiel würden Sie es mit vier Zahlen versuchen und prüfen, ob das Ergebnis 24 ist.

Sie können das automatisieren, indem Sie eine Swift-Funktion schreiben, die den Test für Sie durchführt. Zum Beispiel:

1
2
3
4
5

func testFactorial() {
if factorial(of: 4) != 24 {
print(„Die Fakultät von 3 ist falsch“)
}
}

Dies ist einfacher Swift-Code, den jeder verstehen kann. Alles, was er tut, ist, die Ausgabe der Funktion zu überprüfen und eine Meldung zu drucken, wenn sie nicht korrekt ist.

Das ist Unit Testing in einer Nussschale. Alles andere ist Schnickschnack, den Xcode hinzugefügt hat, um das Testen zu vereinfachen.

Das wäre zumindest der Fall, wenn der Code in unseren Anwendungen so einfach wäre wie die gerade geschriebene Fakultät. Deshalb brauchen Sie die Unterstützung von Xcode und fortgeschrittene Techniken wie Testverdopplungen.

Allerdings ist diese Idee sowohl für einfache als auch für komplexe Tests hilfreich.

Mit Unit-Tests können Sie schwer erreichbare Randfälle überprüfen und Fehler verhindern

Sie können mehrere Vorteile von Unit-Tests haben.

Der offensichtlichste ist, dass Sie Ihren Code nicht ständig manuell testen müssen. Es kann mühsam sein, Ihre Anwendung auszuführen und an eine bestimmte Stelle mit der zu testenden Funktionalität zu gelangen.

Aber das ist noch nicht alles. Mit Unit-Tests können Sie auch Randfälle testen, die in einer laufenden Anwendung schwer zu erstellen sind. Und Randfälle sind die Orte, an denen die meisten Fehler auftreten.

Was passiert zum Beispiel, wenn wir Null oder eine negative Zahl in unsere faktorielle(of:) Funktion von oben eingeben?

1
2
3
4
5

func testFactorialOfZero() {
if factorial(of: 0) != 1 {
print(„Die Fakultät von 0 ist falsch“)
}
}

Unser Code bricht:

In einer realen Anwendung würde dieser Code einen Absturz verursachen. Null liegt außerhalb des Bereichs in der for-Schleife.

Unser Code scheitert aber nicht an einer Einschränkung der Swift-Bereiche. Er schlägt fehl, weil wir vergessen haben, nicht-positive ganze Zahlen in unserem Code zu berücksichtigen. Per Definition gibt es die Fakultät einer negativen ganzen Zahl nicht, während die Fakultät von 0 gleich 1 ist.

1
2
3
4
5
6
7
8
9
10
11
12
13

func factorial(of number: Int) -> Int? {
if (Zahl < 0) {
return nil
}
if (Zahl == 0) {
return 1
}
var result = 1
for factor in 1…number {
result = result * factor
}
return result
}

Wir können nun unsere Tests erneut durchführen und sogar eine Prüfung für negative Zahlen hinzufügen.

1
2
3
4
5

func testFactorialOfNegativeInteger() {
if factorial(of: -1) != nil {
print(„Die Fakultät von -1 ist falsch“)
}
}

Hier sehen Sie den letzten und, meiner Meinung nach, wichtigsten Vorteil von Unit-Tests. Die Tests, die wir zuvor geschrieben haben, stellen sicher, dass wir bei der Aktualisierung der Funktion factorial(of:) den vorhandenen Code nicht beschädigen.

Dies ist in komplexen Anwendungen, in denen Sie ständig Code hinzufügen, aktualisieren und löschen müssen, von entscheidender Bedeutung. Unit-Tests geben Ihnen die Gewissheit, dass Ihre Änderungen keinen gut funktionierenden Code zerstört haben.

Schreiben von Unit-Tests in Xcode

Mit dem Verständnis für Unit-Tests können wir uns nun die Testfunktionen von Xcode ansehen.

Wenn Sie ein neues Xcode-Projekt erstellen, haben Sie die Möglichkeit, sofort Unit-Tests hinzuzufügen. Als Beispiel nehme ich eine App, die Kalorien aufzeichnet. Das vollständige Xcode-Projekt finden Sie hier.

Wenn Sie diese Option aktivieren, enthält Ihr Vorlagenprojekt ein bereits konfiguriertes Testziel. Sie können später immer noch eines hinzufügen, aber ich aktiviere die Option normalerweise standardmäßig. Selbst wenn ich nicht sofort Tests schreibe, ist alles vorbereitet, wenn ich mich dazu entschließe.

Das Testziel enthält bereits einige Vorlagen für unsere Tests.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

import XCTest
@testable import Calories
class CaloriesTests: XCTestCase {
override func setUpWithError() throws {
// Hier wird der Setup-Code platziert. Diese Methode wird vor dem Aufruf jeder Testmethode in der Klasse aufgerufen.
}
override func tearDownWithError() throws {
// Legen Sie hier den Abbruchcode ab. Diese Methode wird nach dem Aufruf jeder Testmethode in der Klasse aufgerufen.
}
func testExample() throws {
// Dies ist ein Beispiel für einen funktionalen Testfall.
// Verwenden Sie XCTAssert und verwandte Funktionen, um zu überprüfen, ob Ihre Tests die richtigen Ergebnisse liefern.
}
func testPerformanceExample() throws {
// Dies ist ein Beispiel für einen Leistungstestfall.
self.measure {
// Fügen Sie hier den Code ein, dessen Zeit Sie messen möchten.
}
}
}

  • Die Zeile @testable import Calories gibt Ihnen Zugriff auf alle Typen im Hauptziel Ihres Projekts. Der Code eines Swift-Moduls ist von außen nicht zugänglich, es sei denn, alle Typen und Methoden sind explizit als öffentlich deklariert. Mit dem @testable-Schlüsselwort können Sie diese Einschränkung umgehen und sogar auf privaten Code zugreifen.
  • Die Klasse CaloriesTests stellt einen Testfall dar, d. h. eine Gruppierung zusammengehöriger Tests. Eine Testfallklasse muss von der Klasse XCTestCase abstammen.
  • Mit der Methode setUpWithError() können Sie eine Standardumgebung für alle Tests in einem Testfall einrichten. Wenn Sie nach Ihren Tests einige Aufräumarbeiten durchführen müssen, verwenden Sie tearDownWithError(). Diese Methoden werden vor und nach jedem Test in einem Testfall ausgeführt. Wir brauchen sie nicht, also können Sie sie löschen.
  • Die Methode testExample() ist ein Test wie die, die wir für unser faktorielles Beispiel geschrieben haben. Sie können Testmethoden benennen, wie Sie wollen, aber sie müssen mit dem Präfix test beginnen, damit Xcode sie erkennt.
  • Und schließlich zeigt Ihnen testPerformanceExample(), wie Sie die Leistung Ihres Codes messen können. Leistungstests sind weniger standardisiert als Unit-Tests, und Sie verwenden sie nur für wichtigen Code, der schnell sein muss. Wir werden auch diese Methode nicht verwenden.

Sie finden alle Ihre Testfälle und relativen Tests im Testnavigator von Xcode aufgelistet.

Sie können neue Testfälle zu Ihrem Projekt hinzufügen, indem Sie einfach neue .swift-Dateien mit Code wie dem obigen erstellen, aber es ist einfacher, das Menü „Hinzufügen“ unten im Testnavigator zu verwenden.

Eine gute Architektur erleichtert das Testen Ihres Codes

In einem echten Projekt haben Sie normalerweise keine losen Funktionen wie in unserem faktoriellen Beispiel. Stattdessen haben Sie Strukturen, Aufzählungen und Klassen, die die verschiedenen Teile Ihrer Anwendung repräsentieren.

Es ist wichtig, dass Sie Ihren Code nach einem Entwurfsmuster wie MVC oder MVVM organisieren. Ein gut strukturierter Code sorgt nicht nur dafür, dass Ihr Code gut organisiert und leichter zu warten ist. Es macht auch Unit-Tests einfacher.

Dies hilft uns auch bei der Beantwortung einer häufig gestellten Frage: Welchen Code sollten Sie zuerst testen?

Die Antwort lautet: Beginnen Sie mit Ihren Modelltypen.

Dafür gibt es mehrere Gründe:

  • Wenn Sie dem MVC-Muster oder einem seiner Derivate folgen, werden Ihre Modelltypen die Geschäftslogik der Domäne enthalten. Ihre gesamte Anwendung hängt von der Korrektheit dieses Codes ab, so dass selbst einige wenige Tests eine erhebliche Auswirkung haben.
  • Modelltypen sind oft Strukturen, die Werttypen sind. Diese sind viel einfacher zu testen als Referenztypen (wir werden gleich sehen, warum).
  • Referenztypen, d.h. Klassen, haben Abhängigkeiten und verursachen Seiteneffekte. Um Unit-Tests für diese zu schreiben, benötigen Sie Test-Doubles (Dummies, Stubs, Fakes, Spies und Mocks) und verwenden ausgefeilte Techniken.
  • Controller (im Sinne von MVC) oder View-Modelle (im Sinne von MVVM) sind oft mit Ressourcen wie Plattenspeicher, einer Datenbank, dem Netzwerk und Gerätesensoren verbunden. Sie können auch parallelen Code ausführen. Dadurch werden Unit-Tests erschwert.
  • Der View-Code wird am häufigsten geändert, was zu spröden Tests führt, die leicht abbrechen. Und niemand repariert gerne kaputte Tests.

Werttypen als reine Funktionen behandeln, um Unit-Tests zu vereinfachen

Lassen Sie uns also einige Modelltypen zu unserer Anwendung hinzufügen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

struct FoodItem {
let name: String
let caloriesFor100Grams: Int
let grams: Int
}
struct Meal {
private(set) var items: =
var calories: Int {
var calories = 0
for item in items {
calories += (item.caloriesFor100Grams / 100) * item.grams
}
return calories
}
mutating func add(_ item: FoodItem) {
items.append(item)
}
}

Die Meal-Struktur enthält eine einfache Logik zum Hinzufügen von Lebensmitteln und zum Berechnen der Gesamtkalorien der enthaltenen Lebensmittel.

Unit-Testing heißt so, weil man seinen Code in separaten Einheiten testen sollte, wobei alle Abhängigkeiten entfernt werden (das gemeinsame Testen von Abhängigkeiten wird stattdessen Integrationstest genannt). Jede Einheit wird dann wie eine Blackbox behandelt. Man füttert sie mit einer Eingabe und testet ihre Ausgabe, um zu prüfen, ob sie den Erwartungen entspricht.

Das war im Fall unseres faktoriellen Beispiels einfach, weil es sich um eine reine Funktion handelte, d. h. eine Funktion, bei der die Ausgabe nur von der Eingabe abhängt und die keine Nebeneffekte erzeugt.

Aber das scheint bei unserem Typ „Meal“ nicht der Fall zu sein, der einen Zustand enthält.

Der von der Eigenschaft „calories computed“ zurückgegebene Wert hat keine Eingabe. Er hängt nur von dem Inhalt des Arrays items ab. Die Methode add(_:) hingegen gibt keinen Wert zurück und ändert nur den internen Zustand einer Mahlzeit.

Aber Strukturen sind Werttypen, und wir können sie als reine Funktionen betrachten. Da sie keine Abhängigkeiten haben, kann man den Anfangszustand einer Struktur als Eingabe einer Methode und ihren Zustand nach dem Aufruf der Methode als Ausgabe betrachten.

(Dies ist einer der Gründe, warum man davon absehen sollte, Referenztypen in Werttypen zu setzen).

Überprüfen Sie Ihren Code mit den Assertions-Funktionen des XCTest-Frameworks

Wir haben jetzt etwas Code zum Testen und einen Platz in unserem Xcode-Projekt, an dem wir die Tests schreiben können.

Eine letzte Zutat fehlt uns noch: eine Möglichkeit, auszudrücken, ob unser Code korrekt ist oder nicht.

Im Beispiel am Anfang dieses Artikels habe ich einfache Print-Anweisungen verwendet. Das ist für echte Unit-Tests nicht praktikabel. Sie möchten keine Zeit damit verschwenden, Protokolle zu durchforsten, um herauszufinden, welche Tests fehlgeschlagen sind. Wir brauchen eine Möglichkeit, die direkt auf fehlgeschlagene Tests verweist.

Im XCTest-Framework finden Sie eine Reihe von Assertion-Funktionen, mit denen Xcode auf Tests verweist, die nicht bestanden haben.

Damit können wir unseren ersten Test schreiben.

Wie ich bereits erwähnt habe, sind Unit-Tests hilfreich, um Randfälle zu überprüfen, also fangen wir damit an, sicherzustellen, dass eine leere Mahlzeit keine Kalorien hat.

1
2
3
4
5
6

class CaloriesTests: XCTestCase {
func testEmptyMeal() throws {
let meal = Meal()
XCTAssertEqual(meal.calories, 0, „Eine leere Mahlzeit sollte 0 Kalorien haben“)
}
}

Der XCTest bietet eine generische XCTAssert-Funktion, mit der Sie jede beliebige Bedingung behaupten können. Sie können diese Funktion für jeden Test verwenden, den Sie schreiben, aber es ist besser, wenn Sie spezialisiertere Assertion-Funktionen verwenden, wie XCTAssertEqual (oben), XCTAssertNil und andere. Diese erzeugen in Xcode bessere Fehler als XCTAssert.

Sie können einen einzelnen Test ausführen, indem Sie auf die Raute neben seinem Namen in der Gosse des Code-Editors klicken.

Wenn ein Test besteht, wird er grün, während fehlgeschlagene Tests rot markiert werden. Sie können die 0 im Test in eine beliebige andere Zahl ändern, um zu sehen, wie ein nicht bestandener Test aussieht.

Sie können alle Tests in einem Testfall ausführen, indem Sie auf die Raute neben der Klassendeklaration klicken. Sie können auch den Testnavigator verwenden, den wir oben gesehen haben, um einzelne Tests oder Testfälle auszuführen.

Oft möchten Sie alle Tests in Ihrem Projekt auf einmal ausführen, was Sie schnell tun können, indem Sie cmd+U auf Ihrer Tastatur drücken oder die Option Test im Produktmenü von Xcode auswählen.

Messen der Codeabdeckung eines Tests in Xcode

Die nächste, häufigste Frage zu Unit-Tests lautet: Wie viel Ihres Codes sollten Sie testen?

Dies wird in der Regel durch die Codeabdeckung gemessen, d. h., der Prozentsatz des Codes, der von den Tests abgedeckt wird. Bevor wir diese Frage beantworten, sehen wir uns an, wie Sie die Codeabdeckung Ihrer Tests in Xcode messen können.

Zuallererst müssen Sie Xcode die Abdeckung für Ihr Testziel erfassen lassen. Klicken Sie auf die Schaltfläche mit dem Projektnamen im segmentierten Steuerelement in der Xcode-Symbolleiste (neben der Stopp-Schaltfläche). Wählen Sie dann Schema bearbeiten… im Popup-Menü.

Wählen Sie dort in der Gliederung Test aus und gehen Sie dann auf die Registerkarte Optionen. Und schließlich wählen Sie Erfassungsbereich für. Sie können die Option auf alle Ziele setzen.

Sie können nun Ihre Tests erneut ausführen, damit Xcode die Abdeckungsdaten erfassen kann. Das Ergebnis finden Sie im Berichtsnavigator, indem Sie in der Gliederung den Punkt Codeabdeckung auswählen.

Hier können Sie den prozentualen Anteil des von Ihren Tests abgedeckten Codes für das gesamte Projekt und jede Datei überprüfen.

Diese Zahlen sind für unser Beispiel nicht sehr aussagekräftig, da wir kaum Code geschrieben haben. Dennoch können wir sehen, dass die add(_:)-Methode des Typs Meal eine Abdeckung von 0 % hat, was bedeutet, dass wir sie noch nicht getestet haben.

Die berechnete Eigenschaft calories hat stattdessen eine Abdeckung von 85,7 %, was bedeutet, dass es einige Ausführungspfade in unserem Code gibt, die unser Test nicht ausgelöst hat.

In unserem einfachen Beispiel ist es einfach zu verstehen, welcher Pfad das ist. Wir haben nur die Kalorien einer leeren Mahlzeit getestet, so dass der Code in der for-Schleife nicht ausgeführt wurde.

Bei anspruchsvolleren Methoden ist das allerdings nicht ganz so einfach.

Dazu können Sie den Codeabdeckungsstreifen im Xcode-Editor einblenden. Sie finden ihn im Menü „Editoroptionen anpassen“ in der oberen rechten Ecke.

Damit wird ein Streifen eingeblendet, der Ihnen die Abdeckung für jede Codezeile anzeigt.

Die Zahlen geben an, wie oft jede Zeile während des Tests ausgeführt wurde. In Rot sehen Sie, welche Zeilen überhaupt nicht (vollständig) oder nur teilweise (gestreift) ausgeführt wurden.

Warum es sinnlos ist, eine bestimmte Codeabdeckung anzustreben, und was Sie stattdessen tun sollten

Welcher Prozentsatz ist also eine gute Codeabdeckung?

Die Meinungen sind sehr unterschiedlich. Einige Entwickler sind der Meinung, dass 20 % ausreichend sind. Andere streben höhere Zahlen an, wie 70% oder 80%. Es gibt sogar Entwickler, die glauben, dass nur 100 % akzeptabel sind.

Meiner Meinung nach ist die Codeabdeckung eine bedeutungslose Metrik. Man kann sie als Entscheidungshilfe für das Testen verwenden, aber man sollte sie nicht als Ziel betrachten, das man erreichen muss.

Um zu sehen, warum, schreiben wir einen weiteren Test, um den Code abzudecken, den wir noch nicht getestet haben.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class CaloriesTests: XCTestCase {
let banana = FoodItem(name: „Banana“, caloriesFor100Grams: 89, grams: 118)
let steak = FoodItem(name: „Steak“, caloriesFor100Grams: 271, grams: 225)
let goatCheese = FoodItem(name: „Ziegenkäse“, caloriesFor100Grams: 364, grams: 28)
func testEmptyMeal() throws {
let meal = Meal()
XCTAssertEqual(meal.calories, 0, „Eine leere Mahlzeit sollte 0 Kalorien haben“)
}
func testCalories() {
var meal = Meal()
meal.add(banana)
meal.add(steak)
meal.add(goatCheese)
XCTAssertEqual(meal.items.count, 3)
XCTAssertEqual(meal.calories, 534)
}
}

Wenn Sie alle Tests noch einmal ausführen, erhalten Sie eine 100%ige Abdeckung für die Datei Model.swift. Sieht gut aus, nicht wahr?

Nun, gehen Sie und entfernen Sie die testEmptyMeal() Methode. Wenn Sie den verbleibenden Test alleine ausführen, werden Sie sehen, dass die Abdeckung für unsere Meal-Typen immer noch 100% beträgt.

Das zeigt Ihnen bereits, dass die 100%-Zahl Ihnen ein falsches Gefühl der Sicherheit geben kann. Sie wissen, dass wir jetzt nicht alle Randfälle für die Eigenschaft „Kalorien berechnet“ testen. Und dennoch spiegelt unsere Testabdeckung dies nicht wider.

Ich möchte hinzufügen, dass eine 100%ige Abdeckung nicht nur irreführend, sondern sogar schädlich ist. Ein Teil des Codes in Ihrem Projekt ist anfällig für ständige Änderungen, insbesondere der neueste Code und vor allem in Ansichten.

Eine 100%ige Abdeckung bedeutet, dass Sie nur spröde Tests produzieren, die ständig brechen und die Sie beheben müssen. Diese Tests entdecken keine Bugs. Sie brechen ab, weil sich die Funktionalität Ihres Codes ändert.

Und hier kommen wir zu dem Punkt, über den niemand spricht.

Tests zu schreiben macht keinen Spaß, auch wenn das manche Entwickler behaupten. Das Korrigieren von Tests macht noch weniger Spaß. Wenn Sie das zu oft tun, werden Sie Unit-Tests hassen und ganz beiseite schieben.

Psychologie ist für die Softwareentwicklung genauso wichtig wie Best Practices. Wir sind keine Maschinen.

Welche Zahl sollte man also anstreben? Das erfordert eine ausführlichere Diskussion, aber hier gebe ich Ihnen eine Zusammenfassung meiner Meinung.

Schreiben Sie nützliche Tests, beginnend mit dem ältesten Code in Ihrem Projekt, der sich nicht ändern wird. Verwenden Sie die Codeabdeckung nur, um festzustellen, welcher Code noch nicht getestet wurde, aber verwenden Sie sie nicht als Ziel oder um zu entscheiden, wann Sie mehr Tests schreiben sollten. Eine Abdeckung von 20 % ist besser als 80 %, wenn Ihre Tests aussagekräftig sind und Sie den richtigen Code testen.

Wie ich bereits erwähnt habe, enthalten Modelltypen den kritischsten Code in Ihrem Projekt, der sich auch am wenigsten ändert. Beginnen Sie also dort.

Ich mache mir normalerweise nicht die Mühe, jeden einzelnen Ausführungspfad zu testen. In einem realen Projekt würde ich zum Beispiel nicht die Methode testEmptyMeal() schreiben, die ich Ihnen oben gezeigt habe. Ja, es ist wichtig, Randfälle zu testen, aber sie sind nicht alle wichtig.

Ich würde normalerweise nur den testCalories()-Test schreiben. Das sagt mir, dass mein Code funktioniert, und es wird mich warnen, wenn ich später einen Fehler mache, wenn ich diese Methode ändere.

Sicher, es deckt nicht jeden Pfad ab, aber dieser Code ist so einfach, dass das nur Zeitverschwendung ist. Es ist wichtiger, seine Zeit damit zu verbringen, echten Code für Funktionen zu schreiben, die den Benutzern helfen, als jeden Ausführungspfad zu testen.

Ich weiß, dass ich für diese Meinung von einigen Entwicklern Kritik einstecken muss, aber das ist mir egal. Die Testabdeckung ist eine dieser Debatten, die nie enden werden.

Der Code, den Sie schreiben, ist in der Regel richtig. Es gibt keinen Grund, paranoid zu sein. Eine Fülle von Tests zu haben, die jedes Mal abbrechen, wenn Sie etwas ändern, ist eine Belastung, kein Vorteil.

Ihre Zeit und Willenskraft sind begrenzt. Verwenden Sie sie für wichtigere Aufgaben.

Architektur von SwiftUI-Anwendungen mit MVC und MVVM

Es ist einfach, eine Anwendung zu erstellen, indem man etwas Code zusammenwürfelt. Aber ohne Best Practices und eine robuste Architektur landet man schnell bei unüberschaubarem Spaghetti-Code. In diesem Leitfaden zeige ich Ihnen, wie Sie SwiftUI-Anwendungen richtig strukturieren.

JETZT DAS KOSTENLOSE BUCH ERHALTEN

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.