Datei search engine test.dart

Aus Info-Theke
Zur Navigation springen Zur Suche springen

Link[Bearbeiten]

Zielsetzung[Bearbeiten]

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[Bearbeiten]

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()[Bearbeiten]

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[Bearbeiten]

void main() {
  final baseDirectory = init();
  final txtFilePattern = join(baseDirectory, '*.txt');
  SearchEngine.storeResult = true;

  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 3 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[Bearbeiten]

  • 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'[Bearbeiten]

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);
  });
});

* engine = SearchEngine.execute([r'*', '.']); Hier ist ein unzulässiger regulärer Ausdruck als Textsuchmuster angegeben: * ist nicht erlaubt, vor dem Stern muss ein Zeichen, eine Zeichenklasse oder eine Klammer stehen. Das Ergebnis der Methode execute muss dann <code<null sein.
* engine = SearchEngine.execute([r'nixda', '*.nix', '--none-known']); Wir verwenden eine unbekannte Option --none-known. Wieder muss das Ergebnis null sein, was mit der Konstante isNull festgelegt wird.
* engine = SearchEngine.execute([]); Keine Argumente anzugeben ist ebenfalls ein Fehler, der als Ergebnis null liefern muss.