Instruments for Apples Xcode ist ein Tool zur Analyse der Leistung einer iOS-Anwendung. Sie werden zum Sammeln und Anzeigen von Daten verwendet, die beim Debuggen von Code benötigt werden. Im vergangenen Jahr hat Apple Custom Instruments eingeführt. Dies ist eine Gelegenheit, den Standardsatz von Tools für die Profilerstellung von Anwendungen zu erweitern. Wenn vorhandene Tools nicht ausreichen, können Sie selbst neue erstellen. Sie erfassen, analysieren und zeigen die Daten nach Bedarf an.
Ein Jahr ist vergangen, und es gibt fast keine neuen öffentlichen Tools und Informationen zu ihrer Erstellung im Netzwerk. Deshalb haben wir uns entschlossen, die Situation zu korrigieren und zu teilen, wie wir unser eigenes benutzerdefiniertes Instrument erstellt haben, das den Grund für die schwache Isolation von Komponententests ermittelt. Es basiert auf der Wegweisertechnologie (darüber haben wir
im vorherigen Artikel geschrieben ) und ermöglicht es Ihnen, schnell und genau zu bestimmen, wo der Test blinkt.

Theoretisches Minimum
Um ein neues Tool für Xcode zu erstellen, müssen Sie zwei theoretische Blöcke verstehen. Für diejenigen, die es selbst herausfinden wollen, werden wir sofort die notwendigen Links geben:
Im Übrigen finden Sie unten eine kurze Zusammenfassung der erforderlichen Themen.
Wählen Sie zuerst Datei -> Neu -> Projekt -> macOS-Kategorie -> Instrumente. Das erstellte Projekt enthält eine Datei mit der Erweiterung .instrpkg, in der ein neues Tool deklarativ im XML-Format deklariert wird. Machen wir uns mit den Markup-Elementen vertraut:
Was | Attribute | Beschreibung
|
Datenschemata
| Intervallschema, Punktschema usw.
| Beschreibt die Datenstruktur als Tabelle wie SQL-Schemata. Schemata werden in anderen Markup-Elementen verwendet, um den Datentyp am Eingang und Ausgang des Modells zu bestimmen, beispielsweise bei der Beschreibung eines Mappings (UI).
|
Datenschemas importieren
| Import-Schema
| Importieren Sie vorgefertigte Schemata. Sie können Datenstrukturen verwenden, die von Apple definiert wurden.
|
Werkzeugmodell
| Modellierer
| Ordnet das Tool einer CLP-Datei zu, in der die Logik des Tools definiert ist, und kündigt das erwartete Datenschema bei der Eingabe und Ausgabe des Modells an.
|
Werkzeugbeschreibung
| Instrument
| Beschreibt das Datenmodell und bestimmt, wie Ereignisse in der Benutzeroberfläche angezeigt werden. Das Datenmodell wird mit den Attributen create-table, create-parameter usw. beschrieben. Werkzeugdiagramme werden durch Diagrammattribute definiert, und die Teiletabelle wird durch Liste, Erzählung usw. definiert.
|
Wenn wir die Logik des neuen Tools ergänzen möchten, erstellen Sie eine CLP-Datei mit CLIPS-Code. Grundlegende Sprachentitäten:
- "Fakt" ist ein bestimmtes Ereignis, das mit dem Befehl assert im System registriert wird.
- "Regel" ist ein if-Block mit einer bestimmten Syntax, die eine Bedingung enthält, unter der eine Reihe von Aktionen ausgeführt wird.
Welche Regeln und in welcher Reihenfolge aktiviert werden, bestimmt der CLIPS selbst anhand der eingehenden Fakten, der Prioritäten der Regeln und des Konfliktlösungsmechanismus.
Die Sprache unterstützt die Erstellung von Datentypen basierend auf Grundelementen, die Verwendung von arithmetischen, logischen Operationen und Funktionen. Sowie vollwertige objektorientierte Programmierung (OOP) mit der Definition von Klassen, Senden von Nachrichten, Mehrfachvererbung.
Betrachten Sie die grundlegende Syntax einer Sprache, mit der Sie Logik für benutzerdefinierte Tools erstellen können.
1. Um eine
fact
zu erstellen, verwenden Sie das
assert
Konstrukt:
CLIPS> (assert (duck))
So erhalten wir den
duck
in der Faktentabelle, der mit dem Befehl fact angezeigt werden kann:
CLIPS> (facts)
Verwenden Sie den Befehl zum
retract
um die Tatsache zu beseitigen:
(retract duck)
2. Um eine
rule
zu erstellen, verwenden Sie das
defrule
Konstrukt:
CLIPS> (defrule duck) — duck (animal-is duck)</i> — animal-is duck => (assert (sound-is quack))) — sound-is quack
3. Zum Erstellen und Verwenden von Variablen wird die folgende Syntax verwendet (vor dem Variablennamen steht ein Pflichtzeichen "?"):
?<variable-name>
4. Sie können neue Datentypen erstellen mit:
CLIPS> (deftemplate prospect (slot name (type STRING) (default ?DERIVE)) (slot assets (type SYMBOL) (default rich)) (slot age (type NUMBER) (default 80)))
Daher haben wir eine Struktur mit dem Namen "Interessent" und den drei Attributen "Name", "Assets" und "Alter" des entsprechenden Typs sowie einem Standardwert definiert.
5. Arithmetische und logische Operationen haben eine Präfixsyntax. Das heißt, um 2 und 3 hinzuzufügen, müssen Sie die folgende Konstruktion verwenden:
CLIPS> (+ 2 3)
Oder um zwei Variablen x und y zu vergleichen:
CLIPS> (> ?x ?y)
Praktisches Beispiel
In unserem Projekt verwenden wir die
OCMock- Bibliothek, um Stub-Objekte zu erstellen. Es gibt jedoch Situationen, in denen ein Mok länger lebt als der Test, für den er erstellt wurde, und die Isolation anderer Tests beeinflusst. Dies führt zum „Blinken“ (Instabilität) von Unit-Tests. Um die Lebensdauer von Tests und Verspottungen zu verfolgen, werden wir unser eigenes Tool erstellen. Das Folgende ist ein Algorithmus von Aktionen.
Schritt 1. Markup für Wegweiserereignisse erstellen
Um problematische Moxes zu erkennen, werden zwei Kategorien von Intervallereignissen benötigt - der Zeitpunkt der Erstellung und Zerstörung des Moxas, die Start- und Endzeit des Tests. Um diese Ereignisse
OCMock
die
OCMock
Bibliothek auf und
OCMock
Sie sie mit einem
signpost
in den Methoden
init
und
stopMocking
der Klasse
stopMocking
.


Gehen Sie als Nächstes zum untersuchten Projekt und führen Sie das Markup in Unit-Tests,
setUp
und
tearDown
:

Schritt 2. Erstellen Sie ein neues Werkzeug aus der Instrumentenpaketvorlage

Zunächst bestimmen wir den Datentyp der Eingabe. Dazu importieren
.instrpkg
das
signpost
in die
signpost
. Jetzt fallen Ereignisse, die vom
signpost
erstellt wurden, in das Tool:

Als nächstes bestimmen wir den Datentyp in der Ausgabe. In diesem Beispiel werden simultane Ereignisse ausgegeben. Jede Veranstaltung hat eine Zeit und eine Beschreibung. Deklarieren Sie dazu das Schema:

Schritt 3. Wir beschreiben die Logik des Werkzeugs
Wir erstellen eine separate Datei mit der Erweiterung
.clp
, in der wir die Regeln mithilfe der CLIPS-Sprache festlegen.
modeler
Sie den
modeler
hinzu, um dem neuen Tool mitzuteilen, in welcher Datei die Logik definiert ist:

Geben Sie in diesem Block mithilfe des
production-system
den relativen Pfad zur Datei mit der Logik an. In den Attributen
output
und
required-input
definieren
required-input
die Datenschemata für Eingabe bzw. Ausgabe.

Schritt 4. Wir beschreiben die Besonderheiten der Präsentation des Tools (UI).
In der
.instrpkg
Datei muss das Tool selbst beschrieben werden,
.instrpkg
die Ergebnisse werden
.instrpkg
. Erstellen Sie eine Tabelle für die Daten im Attribut "
create-table
Verwendung des zuvor deklarierten
schema-ref
detected-mocks-narrative
im Attribut "
schema-ref
. Und richten Sie die Art der Informationsausgabe ein - narrativ (beschreibend):

Schritt 5. Wir schreiben den Logikcode
.clp
wir mit der
.clp
Datei fort, in der die Logik des Expertensystems definiert ist. Die Logik lautet wie folgt: Wenn sich die Startzeit des Tests mit dem Intervall des Lebens des Moka überschneidet, glauben wir, dass dieser Mok aus einem anderen Test „stammt“ - was die Isolation des aktuellen Unit-Tests verletzt. Um schließlich ein Ereignis mit interessanten Informationen zu erstellen, müssen Sie die folgenden Schritte ausführen:
1. Definieren Sie die Strukturen mock und unitTest mit Feldern - dem Zeitpunkt des Ereignisses, der Ereigniskennung, dem Namen des Tests und der Klasse des Mok.

2. Wir definieren die Regeln, die Fakten mit den Typen
mock
und
unitTest
basierend auf den eingehenden Ereignissen des
signpost
erstellen:

Diese Regeln können wie folgt gelesen werden: Wenn wir bei der Eingabe einen Fakt vom Typ os-signpost mit dem gewünschten
subsystem
, der gewünschten
category
, dem gewünschten
name
und dem gewünschten
event-type
, erstellen Sie einen neuen Fakt mit dem oben definierten Typ (unitTest oder mock) und füllen Sie ihn mit Werten. Hierbei ist zu beachten, dass bei CLIPS zwischen Groß- und Kleinschreibung unterschieden wird und die Werte für Subsystem, Kategorie, Name und Ereignistyp mit den Werten im Code des untersuchten Projekts übereinstimmen müssen.

Variablen von Wegweiserereignissen werden wie folgt übergeben:

3. Wir definieren die Regeln, die abgeschlossene Ereignisse freigeben (sie sind redundant, da sie das Ergebnis nicht beeinflussen).

Schritt 6. Definieren Sie die Regel, die die Ergebnisse generiert.
Sie können die Regel so lesen.
Wenn1) es gibt unitTest und mock;
2) in diesem Fall erfolgt der Beginn des Tests später als der vorhandene Moka;
3) es gibt eine Tabelle zum Speichern von Ergebnissen mit dem Schema der erkannten Verspottungserzählung;
dann4) einen neuen Datensatz erstellen;
5) mit der Zeit ausfüllen;
6) ... und eine Beschreibung.

Als Ergebnis sehen wir das folgende Bild, wenn Sie das neue Tool verwenden:

Der Quellcode für ein benutzerdefiniertes Instrument und ein Beispielprojekt für die Verwendung des Instruments können
auf GitHub angezeigt werden.
Tool-Debugging
Der Debugger wird zum Debuggen benutzerdefinierter Tools verwendet.

Er erlaubt
1. Siehe kompilierten Code basierend auf der Beschreibung in instrpkg.
2. Sehen Sie sich detaillierte Informationen darüber an, was zur Laufzeit mit dem Tool passiert.

3. Zeigen Sie eine vollständige Liste und Beschreibung der Systemdatenschemata an, die als Eingabe in neue Tools verwendet werden können.

4. Führen Sie beliebige Befehle in der Konsole aus. Zeigen Sie beispielsweise eine Liste von Regeln mit dem Befehl list-defrules oder Fakten mit dem Befehl fact an

Einrichtung auf dem CI-Server
Sie können Tools über die Befehlszeile ausführen, um die Anwendung während der Ausführung von Unit- oder UI-Tests auf dem CI-Server zu profilieren. So kann beispielsweise ein Speicherverlust so früh wie möglich erkannt werden. Verwenden Sie die folgenden Befehle, um Tests in der Pipeline zu profilieren:
1. Ausführen von Tools mit Attributen:
xcrun instruments -t <template_name> -l <average_duration_ms> -w <device_udid>
- Dabei ist
template_name
der Pfad zur Vorlage mit den Werkzeugen oder der Name der Vorlage. Sie können den Befehl xcrun instruments -s
; average_duration_ms
- Die Aufnahmezeit in Millisekunden sollte größer oder gleich der Testlaufzeit sein.device_udid
- Simulator- device_udid
. Sie können den Befehl xcrun Instrumente -s erhalten. Muss mit der Kennung des Simulators übereinstimmen, auf dem die Tests ausgeführt werden.
2. Ausführen von Tests auf demselben Simulator mit dem folgenden Befehl:
xcodebuild -workspace <path_to_workspace>-scheme <scheme_with_tests> -destination <device> test-without-building
- Dabei ist
path_to_workspace
der Pfad zum Xcode-Arbeitsbereich. scheme_with_tests
- Schema mit Tests;device
- Simulator-ID.
Als Ergebnis wird im Arbeitsverzeichnis ein Bericht mit der Erweiterung .trace erstellt, der von der Anwendung Instruments oder durch Klicken mit der rechten Maustaste auf die Datei und Auswahl von Paketinhalt anzeigen geöffnet werden kann.
Schlussfolgerungen
Wir haben uns ein Beispiel für das Upgrade eines Wegweisers auf ein vollwertiges Tool angesehen und erklärt, wie es automatisch auf die "Läufe" des CI-Servers angewendet und zur Lösung des Problems "blinkender" (instabiler) Tests verwendet werden kann.
Wenn Sie sich mit den Möglichkeiten kundenspezifischer Instrumente befassen, werden Sie besser verstehen, in welchen anderen Fällen Sie die Instrumente verwenden können. Sie helfen uns beispielsweise auch dabei, die Probleme des Multithreading zu verstehen - wo und wann der thread-sichere Datenzugriff verwendet werden soll.
Das Erstellen eines neuen Tools war recht einfach. Die Hauptsache ist jedoch, dass Sie nach mehreren Tagen, in denen Sie die Mechanik und Dokumentation studiert haben, um sie heute zu erstellen, mehrere schlaflose Nächte vermeiden können, wenn Sie versuchen, Fehler zu beheben.
Quellen
Der Artikel wurde mit @regno , Anton Vlasov, einem iOS-Entwickler, geschrieben.