[JAVA] Beziehung zwischen UI-Test und Aufzeichnung, Implementierungsmethode

Dieser Artikel ist der 20. Tag von Recruit Lifestyle Adventskalender 2017.

Einführung

Mein Name ist @AHA_oretama und mein erstes Kind wurde vorgestern geboren. Ich war mit verschiedenen privaten Veranstaltungen beschäftigt und habe etwas spät gepostet, aber bitte vergib mir!

Normalerweise rekrutiere und mache ich eine Aktivität namens R-SET. Das Wort SET selbst ist eine von Google befürwortete Rolle und wurde in Google Testing Blog eingeführt. Ich bin. Der Auszug aus dem Erklärungsteil von SET lautet wie folgt.

The SET or Software Engineer in Test is also a developer role except their focus is on testability.

Zusammenfassend ist es ein Ingenieur, der sich auf Testbarkeit → SET konzentriert.

R-SET ist ein geprägtes Wort, das zur Verbesserung der Suchbarkeit erstellt wurde und wie folgt definiert ist.

R-SET is Recruit Lifestyle's SET.

Bei R-SET durch Verbesserung der Testbarkeit von Rekrutierungs-Lifestyle-Diensten

Ist als Mission aufgeführt.

Nachdem wir es eingeführt haben, möchte ich über die Aufzeichnung des UI-Tests der App sprechen.

Informationen zu UI-Testeigenschaften und Aufnahmefunktion

Stellen Sie zunächst sicher, dass Sie über den hier genannten UI-Test informiert sind.

スクリーンショット 2017-12-20 18.57.53.png

Kennen Sie das Wort Testpyramide? ?? Die Testpyramide ist ein Diagramm, das die Eigenschaften der zu automatisierenden Tests zeigt. Die UI-Tests, Integrationstests und Komponententests sind in der Reihenfolge von oben angeordnet. Im Allgemeinen bezieht sich der UI-Test häufig auf einen End-to-End-Test, bei dem alle Module und externen Dienste verbunden sind.

Dieses Mal wird derjenige, der dieser Testpyramide entspricht, als UI-Test bezeichnet.

Als Merkmal der Pyramide repräsentiert die Größe der Pyramide das ideale Verhältnis der Anzahl der Testfälle für die Automatisierung. Mit anderen Worten, es wird gesagt, dass es ideal ist, viele Unit-Tests und nicht zu viele UI-Tests durchzuführen. Es hat auch die Eigenschaften, instabil zu sein, länger zu dauern, um Tests durchzuführen, und teurer, wenn Sie die Pyramide hinaufsteigen.

Und die Eigenschaften dieses UI-Tests führen dazu, dass eine Aufzeichnung erforderlich ist.

Die Automatisierung bietet eine Reihe von Vorteilen, darunter Kosteneinsparungen. Aufgrund ihrer Eigenschaften sind UI-Tests jedoch in der Regel instabile Tests. Wenn Sie UI-Tests durchgeführt haben, haben Sie Dinge erlebt wie: Manchmal ist der Test erfolgreich und manchmal schlägt der Test fehl, obwohl Sie die Quelle nicht geändert haben. Ist es nicht? Wenn ein Test fehlschlägt, müssen Sie die Ursache des Testfehlers ermitteln. Es handelt sich jedoch um einen instabilen Test, und es ist nicht immer möglich, den fehlgeschlagenen Test erneut abzuspielen. Wenn Sie es nicht immer wieder ausführen, kann derselbe Status nicht reproduziert werden, und es wird einige Zeit dauern, bis die Ursache untersucht ist. Ein weiteres Merkmal von UI-Tests ist, dass ihre Ausführung lange dauert. Je näher der fehlgeschlagene Test am Ende des Testszenarios liegt, desto länger dauert es, bis dieser Status erreicht ist.

Hast du bemerkt? Obwohl die Vorteile der Automatisierung Kosteneinsparungen sind, ist die Wartung automatisierter Tests kostspielig und die Vorteile gehen verloren!

Was aber, wenn der fehlgeschlagene Test zu diesem Zeitpunkt aufgezeichnet wurde?

Zum Beispiel

Sie werden oft in der Lage sein, die Ursache zu verstehen.

Kurz gesagt, die Aufzeichnung ist eine Reaktion auf die Instabilität von UI-Tests und erhöhte Kosten aufgrund langer Ausführungszeiten, die erforderlich sind, um effektiv von der Automatisierung zu profitieren.

Wie man aufnimmt

Nachdem wir nun wissen, wie wichtig das Aufzeichnen im UI-Test ist, sprechen wir über das Aufzeichnen. Dieses Mal werde ich mich auf Apps konzentrieren, daher möchte ich das WEB vorstellen, wenn es eine andere Gelegenheit gibt.

Aufnahme auf Android-Geräten

Die Aufzeichnung auf Android-Geräten kann mit dem folgenden ADB-Befehl ausgeführt werden.

adb shell screenrecord {filename}

Sie können es mit Strg + C stoppen.

Hier wird die Ausgabedatei auf dem Android-Gerät gespeichert. Da Dateiname der Dateiname auf dem Android-Gerät ist, sieht er wie folgt aus: / sdcard / demo.mp4.

Ich denke, dass auf Android-Geräten gespeicherte Dateien oft auf dem lokalen PC gespeichert werden. Mit dem folgenden ADB-Befehl können Sie eine Datei auf Ihrem Android-Gerät auf Ihrem lokalen PC erstellen.

adb pull {remote} {local}

Laut Benutzerhandbuch wird die Aufnahmefunktion für Android 4.4 (API-Level 19) oder höher unterstützt. ,Achtung. Beachten Sie auch, dass die maximale Aufnahmezeit maximal 180 Sekunden (3 Minuten) beträgt.

iOS Simulator Aufnahme

Die Aufzeichnung von iOS Simulator kann mit dem folgenden Befehl des Xcode-Befehlszeilenprogramms ausgeführt werden.

xcrun simctl io booted recordVideo {filename}

Im Fall von iOS Simulator ist das Speicherziel der lokale PC. iOS kann auch mit "Strg + C" gestoppt werden.

Laut Versionshinweisen Bitte beachten Sie, dass diese Aufnahmefunktion eine Funktion von Xcode 8.2 ist.

Implementierung in Java

Wir werden in Java die Möglichkeit implementieren, UI-Tests mit Appium zu erstellen und diese Tests aufzuzeichnen. Während es in Appium viele japanische Dokumente für Ruby gibt, gibt es nur wenige japanische Dokumente für andere Sprachen (obwohl die ursprüngliche englische Site auch ... ist). Daher halte ich es für sinnvoll, Appium-Funktionen in Java zu schreiben. Ich werde.

Hier ist eine konkrete Umsetzung.

Es ist eine Umgebung für alle Fälle, aber ich habe es in der folgenden Umgebung bestätigt.

Lassen Sie uns die Implementierung vorstellen.

public class RecordFactory {

    public static RecordFactory factory = new RecordFactory();

    public static RecordFactory getInstance() {
        return factory;
    }

    public Record createRecord(AppiumDriver driver, String fileName, String output) {
        if (driver.getPlatformName().equals("Android")) {
            return new AdbRecord(fileName, output);
        } else {
            return new iOSSimulatorRecord(fileName, output);
        }
    }
}
interface Record extends Closeable {
  void start()
}

Erläuterung des obigen Codes. Sie können das Ausführungsterminal (Android oder iOS) mit "AppiumDriver.getPlatformName ()" erhalten. Appium hat den Vorteil, ein plattformübergreifendes UI-Testtool zu sein. Daher ermöglichen wir hier die Verwendung unabhängig vom Aufzeichnungsterminal, indem wir eine Factory-Klasse erstellen, die das laufende Terminal bestimmt und eine entsprechende Klasse erstellt. Ich werde. Da es während des Aufnahmeprozesses ein Bild von "Closeable" gab, habe ich diese Schnittstelle hinzugefügt, aber ich denke, dass es in Ordnung ist, auch wenn es nichts Besonderes gibt.

public class AdbRecord implements Record {

    private final String fileName;
    private final String outputDir;
    private Process recordProcess;
    private final String outputPath;

    AdbRecord(String fileName,String outputDir) {
        this.fileName = fileName.endsWith(".mp4") ? fileName : fileName + ".mp4";
        this.outputDir = outputDir;
        this.outputPath = outputDir + "/" + fileName;
    }

    @Override
    public void start() throws IOException {
        ProcessBuilder builder =
            new ProcessBuilder("adb", "shell", "screenrecord", "/sdcard/" + fileName);
        builder.redirectErrorStream(true);

        recordProcess = builder.start();
    }

    @Override
    public void close() throws IOException {
        if (recordProcess != null) {
            int pid = 0;
            try {
                Field field = recordProcess.getClass().getDeclaredField("pid");
                field.setAccessible(true);
                pid = field.getInt(recordProcess);
            } catch (IllegalAccessException | NoSuchFieldException e) {
                e.printStackTrace();
            }

            while(true) {
                ProcessBuilder builder = new ProcessBuilder("kill", "-2", String.valueOf(pid));
                builder.start();
                TestUtils.sleep(1000);
                if(!recordProcess.isAlive()) {
                    break;
                }
            }
        }

        File dir = new File(outputDir);
        if(!dir.exists()) {
            dir.mkdir();
        }

        //Schlaf, da es eine leichte Zeitverzögerung gibt, bis die Videodatei fertig ist
        TestUtils.sleep(3000);

        //Kopieren Sie Videodateien lokal auf Android-Geräten
        execProcess("adb", "pull", "/sdcard/" + fileName, outputPath);
        //Löschen Sie Videodateien auf Android-Geräten
        execProcess("adb", "shell", "rm", "-f","/sdcard/" + fileName);

        try (InputStream stream = Files.newInputStream(Paths.get(outputPath))) {
            Allure.addAttachment(fileName, stream);
        }
    }

    private void execProcess(String... args) throws IOException {
        ProcessBuilder builder = new ProcessBuilder(args);
        Process process = builder.start();
        try {
            process.waitFor(20, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class iOSSimulatorRecord implements Record {

    private Process recordProcess;
    private final String fileName;
    private final File outputDir;
    private final String outputPath;

    iOSSimulatorRecord(String fileName, String outputDir) {
        this.fileName = fileName.endsWith(".mov") ? fileName : fileName + ".mov";
        this.outputDir = new File(outputDir);
        this.outputPath = this.outputDir.getAbsolutePath() + "/" + fileName;
    }

    @Override
    public void start() throws IOException {
        if(!outputDir.exists()) {
            outputDir.mkdir();
        }

        ProcessBuilder builder =
            new ProcessBuilder("xcrun", "simctl", "io", "booted", "recordVideo", outputPath);
        builder.redirectErrorStream(true);

        recordProcess = builder.start();
    }

    @Override
    public void close() throws IOException {

        if (recordProcess != null) {
            int pid = 0;
            try {
                Field field = recordProcess.getClass().getDeclaredField("pid");
                field.setAccessible(true);
                pid = field.getInt(recordProcess);
            } catch (IllegalAccessException | NoSuchFieldException e) {
                e.printStackTrace();
            }

            while(true) {
                ProcessBuilder builder = new ProcessBuilder("kill", "-2", String.valueOf(pid));
                builder.start();
                TestUtils.sleep(1000);
                if(!recordProcess.isAlive()) {
                    break;
                }
            }
        }
    }
}

Sowohl Android als auch iOS verwenden die Java-Prozessklasse, um den Aufzeichnungsprozess für jedes Terminal zu starten. In Java ist das Abrufen der PID so kompliziert, dass es kompliziert ist, aber Sie müssen nur die PID abrufen. Android unterscheidet sich von iOS darin, dass es nach der Aufnahme auf dem lokalen PC gespeichert werden muss.

Der Benutzer kann es wie folgt verwenden.

        try (Record record = recordFactory.createRecord(driver, fileName, BUILD_REPORTS_RECORDS)) {
            record.start();
            // "Führen Sie den UI-Test aus"
        }

Auf diese Weise können Sie auch in Java aufnehmen.

Schließlich

Die Entwicklung von Testfällen mit Appium steckt noch in den Kinderschuhen, und ich denke, dass verschiedene Dinge in Betrieb und Entwicklung herauskommen werden, daher möchte ich sie bei Bedarf erneut vorstellen.

Recommended Posts

Beziehung zwischen UI-Test und Aufzeichnung, Implementierungsmethode
Beziehung zwischen Paket und Klasse
Unterschied zwischen Instanzmethode und Klassenmethode
Unterschied zwischen == Operator und Methode gleich
Unterschied zwischen dem Operator == und der Methode eqals
[Java] Beziehung zwischen H2DB und JDBC
[Java] Einführungsstruktur Klassendefinition Beziehung zwischen Klasse und Instanz Methodendefinitionsformat
Beziehung zwischen Kotlin- und Java-Zugriffsmodifikatoren
Beziehung zwischen dem Eclipse m2e-Plug-In und Maven
[Schienen] Unterschied zwischen Erstellungsmethode und neuer + Speichermethode
CRUD- und Ressourcenmethode ~ 3 Keine geheime Beziehung ~
So senden Sie Ethereum-Transaktionen Unterschied zwischen send und sendAsync
Informationen zur Beziehung zwischen HTTP-Methoden, Aktionen und CRUD
Überprüfung der Beziehung zwischen dem Docker-Image und dem Container