Datei search_engine_test.dart - flutter-tutorial-de/dart-programming GitHub Wiki

Table of Contents

Link

Zielsetzung

Die Datei search_engine_test.dart enthält die Unittests der Datei search_engine.dart.

Für jede Funktion aus search_engine.dart existiert mindestens ein Test.

Import

import 'dart:io';
import 'package:dgrep/helper.dart';
import 'package:dgrep/search_engine.dart';
import 'package:path/path.dart';
import 'package:test/test.dart';
  • import 'package:dgrep/search_engine.dart'; Damit kennt der Compiler die Definitionen aus search_engine.dart.
  • Die anderen Importe betreffen das interne Paket dart:io und die externen Pakete args, test und path.

Die Funktion init()

Unser Unittest braucht Daten, genauer Dateien, die dann durchsucht werden können. Diese Dateien werden in der Funktion init() erzeugt.

String init() {
  final base = join(Directory.systemTemp.path, 'dgrep');
  writeString(join(base, 'text1.txt'), string: '''Eine Zeile ohne Zahl.
3 Chinesen mit dem Kontrabass.
Blub
''');
  writeString(join(base, 'text1.data'), string: '333');
  final file2 = join(base, 'dir1', 'text2.txt');
  writeString(file2, string: 'Teil2\nder Rest steht:\nIn Zeile 3, TEIL 3');
  final file3 = join(base, 'dir1', 'text3.text');
  writeString(file3, string: '''nix1
nix2
toll3
nix4
toll5
nix6
nix7
nix8
toll9
nix10
''');
  return base;
}
  • final base = path.join(Directory.systemTemp.path, 'dgrep'); Damit der Test plattformunabhängig ist, also unter Linux und Windows funktioniert, fragen wir mit Directory.systemTemp.path den Namen des temporären Verzeichnisses ab, unter Linux ist das '/tmp', unter Windows 'c:\temp' oder ähnliches. Dieses Verzeichnis wird mit der Funktion join() mit dem Unterverzeichnis namens dgrep ergänzt, so dass in base dann unter Linux /tmp/dgrep und unter Windows c:\temp\dgrep steht.
  • writeString(join(base, 'text1.data'), string: '333');
    • join(base, 'text1.data') setzt den Dateinamen aus Basisverzeichnis und Namen text1.data zusammen.
    • writeString schreibt den String 333 in diese Datei.
  • writeString(file3, string: ... Hier wird ein mehrzeiliger String benutzt, der mit jeweils drei Appostrophen umrahmt ist. Das gestaltet den Programmtext übersichtlicher als die Zeilentrenner mit dem Metazeichen \n einzutragen.
  • return base; Das Ergebnis der Funktion ist das Basisverzeichnis.

Hauptprogramm und erster Test

  group('search', () {
    test('recursive search', () {
      final engine = SearchEngine.execute([
        r'\d',
        '*.y~!X',
        txtFilePattern,
        '--recursive',
      ]);
      expect(engine.lines.length, 3);
      expect(engine.lines[0],
          endsWith('text1.txt-2: 3 Chinesen mit dem Kontrabass.'));
      expect(engine.lines[1], endsWith('text2.txt-1: Teil2'));
      expect(engine.lines[2], endsWith('text2.txt-3: In Zeile 3, TEIL 3'));
    });
...
}
  • Jeder Unittest ist ein normales Programm, braucht daher eine Funktion main.
  • SearchEngine.storeResult = true; Damit die Suchergebnisse in der Klasse SearchEngine gespeichert werden, setzen wir das statische Attribut storeResult auf true.
  • Die Tests können mittels der Funktion group() gruppiert werden, das steigert die Übersicht.
  • test('recursive search', () { ... }); Der eigentliche Test findet in der Callbackfunktion (dem zweiten Parameter) der Funktion test() statt.
  • final engine = SearchEngine.execute([r'\d', ...]);
    • Der Aufruf der statischen Methode execute() bekommt die Simulation der Programmargumente übergeben.
    • Dies entspricht dem Aufruf in der Eingabeaufforderung:
    • dgrep \d *.y~!X c:\temp\dgrep\*.txt --recursive
    • oder in Linux:
    • dgrep '\d' '*.y~!X' '/tmp/dgrep/*.txt' --recursive
  • Wir suchen also eine Dezimalziffer (als regulärer Ausdruck: \d) in den Dateien, die im aktuellen Verzeichnis liegen und die Endung .y~!X oder im Basisverzeichnis liegen, mit der Endung .txt. Es wird auch in Unterverzeichnissen (--recursive) gesucht. Das erste Dateisuchmuster *.y~!X ist so gewählt, dass damit keine Dateien gefunden werden, aber normalerweise etliche Unterverzeichnisse durchlaufen werden. Wir testen gleichzeitig, ob die Angabe von zwei Dateisuchmustern funktioniert.
  • Die Funktion expect() hat als ersten Parameter den zu testenden Wert, als zweiten den erwarteten Wert.
  • expect(engine.lines.length, 3);
    • Da wir oben das Attribut SearchEngine.storeResult gesetzt haben, landen die Trefferzeilen im Attribut lines, das eine Stringliste ist. Wir erwarten also drei Trefferzeilen.
  • expect(engine.lines[0], endsWith('text1.txt-2: 3 Chinesen mit dem Kontrabass.'));
    • Die Trefferzeile beginnt mit dem vollen Dateinamen, der unter Linux bzw. Windows verschieden ist. Daher prüfen wir nur den Rest der Zeile mit endsWith().
  • Analog werden die zwei anderen Zeilen getestet.

Die weiteren Tests

  • Die weiteren Tests laufen nach dem gleichem Schema wie der erste Test ab.
  • Jeder Test prüft die Funktion einer Option bzw. die Kombination von Optionen.

Die Gruppe 'errors'

Die zweite Gruppe ist mit 'errors' als Beschreibung gekennzeichnet: Sie prüft die Fehlersituationen:

group('errors', () {
  test('wrong pattern', () {
    final engine = SearchEngine.execute([r'*', '.']);
    expect(engine.lines.length, 0);
  });
  test('unknown option', () {
    final engine = SearchEngine.execute([r'nixda', '*.nix', '--none-known']);
    expect(engine, isNull);
  });
  test('to few arguments', () {
    final engine = SearchEngine.execute([]);
    expect(engine, isNull);
  });
});
</code>
* <code>engine = SearchEngine.execute([r'*', '.']);</code> Hier ist ein unzulässiger regulärer Ausdruck als Textsuchmuster angegeben: <code>*</code> ist nicht erlaubt, vor dem Stern muss ein Zeichen, eine Zeichenklasse oder eine Klammer stehen. Das Ergebnis der Methode <code>execute</code> muss dann <code<null</code> sein.
* <code>engine = SearchEngine.execute([r'nixda', '*.nix', '--none-known']);</code> Wir verwenden eine unbekannte Option <code>--none-known</code>. Wieder muss das Ergebnis <code>null</code> sein, was mit der Konstante <code>isNull</code> festgelegt wird.
* <code>engine = SearchEngine.execute([]);</code> Keine Argumente anzugeben ist ebenfalls ein Fehler, der als Ergebnis <code>null</code>
liefern muss.
⚠️ **GitHub.com Fallback** ⚠️