Dojos für Entwickler 2. Stefan Lieser
Чтение книги онлайн.
Читать онлайн книгу Dojos für Entwickler 2 - Stefan Lieser страница 6
Auf diese Weise lassen sich nun zwar alle Metadaten auslesen, allerdings hat dieser generische Ansatz den Nachteil, dass die gelieferten Werte dann vom Typ object sind. Man muss die Werte daher gegebenenfalls auf den korrekten Typ casten.
Erstaunen und Ärger
Nach diesen Spikes dachte ich, es könne mit der Lösung der Aufgabenstellung losgehen. Doch es zeigte sich, dass nicht alle Programme dasselbe Verfahren zur Ablage von Stichwörtern verwenden. Für meine Spikes hatte ich mit dem Windows Explorer Stichwörter an JPEG-Dateien gesetzt. Abbildung 1 zeigt die Dateieigenschaften.
[Abb. 1]
Stichwörter mit dem Windows Explorer vergeben.
Diese Stichwörter lassen sich mit dem im Spike gezeigten Verfahren über metadata.Keywords leicht auslesen. Doch schon mein erster Versuch, die Stichwörter eines Fotos auszulesen, die ich mit dem Adobe Photoshop Elements Organizer an die Datei gesetzt hatte, schlug fehl. Eine kurze Kontrolle mit dem Windows Explorer zeigte: Auch hier keine Spur von Stichwörtern zu sehen. Das liegt daran, dass der Elements Organizer die Stichwörter in einer eigenen Datenbank ablegt. Dagegen ist ja an sich nichts einzuwenden. Ich vermute mal, dass die Suche in einem großen Fotobestand ohne eigene Datenbank sehr langsam wäre. Doch was mir nicht einleuchten will, ist die Tatsache, dass der Elements Organizer die Stichwörter nicht parallel auch in der JPEG-Datei ablegt. Zwar kann man das durch einen Export erreichen, doch den muss man explizit starten. Und wenn man anschließend Stichwörter oder deren Zuordnung ändert, muss man diese erneut exportieren.
Eine kurze Recherche erbrachte, dass Adobe nicht der einzige Hersteller ist, der diesen Weg gewählt hat. Ich halte das für keine gute Lösung, denn dadurch wird der Zugriff auf einen verschlagworteten Fotobestand von mehreren Arbeitsplätzen aus oder auch mit unterschiedlichen Programmen unnötig verkompliziert. Besonders ärgerlich finde ich, dass die eigens für Stichwörter vorgesehenen Metadaten in den Bilddateien nicht genutzt werden. Dann hätte man sich die ganze Standardisierung auch gleich sparen können. Ein weiteres Ärgernis: Beim Export der Stichwörter ignoriert Adobe leider die Hierarchie und exportiert die Stichwörter ohne die Struktur. „Motive/Kirchen“ wird zu „Kirchen“, „Personen/Familie/Stefan“ wird zu „Stefan“. Das ist sehr schade.
Erste Iteration
Als mein Ärger über diese unschöne Vorgehensweise der Softwarehersteller etwas verflogen war, habe ich begonnen, die erste Iteration der Lösung zu entwickeln. In der ersten Iteration möchte ich ein Verzeichnis rekursiv durchsuchen und die Stichwörter der gefundenen Dateien auf der Konsole ausgeben. Natürlich sollen dabei mehrfach vorkommende Stichwörter nur einmal ausgegeben werden.
Den Entwurf für die erste Iteration zeigt Abbildung 2. Ich gehe in drei Schritten vor:
Die Dateinamen werden ermittelt.
Zu den gefundenen Dateinamen werden die Stichwörter ermittelt.
Die gefundenen Stichwörter werden so gefiltert, dass nur eindeutige Stichwörter übrig bleiben.
[Abb. 2]
Stichwörter mit dem Windows Explorer vergeben.
Mal nicht Test-first
Durch die drei im Entwurf gezeigten Bauteile habe ich mich von oben nach unten durchgearbeitet. Dabei habe ich diesmal nicht Tests zuerst geschrieben, sondern zuerst implementiert und dann Tests geschrieben. Das hat hier gut funktioniert, da durch den Entwurf klar war, was die Bauteile machen sollen. Ferner gibt es keine Abhängigkeiten, sodass die Tests flüssig von der Hand gingen. Zu beachten ist allerdings, dass zwei von den drei Bauteilen von der externen Ressource Dateisystem beziehungsweise von JPEG-Dateien abhängig sind. Dies musste ich natürlich bei den automatisierten Tests berücksichtigen.
Listing 3 zeigt die Implementation für das Bauteil Dateinamen_suchen.
Die eigentliche Arbeit übernimmt die statische Methode Directory.EnumerateFiles aus dem .NET Framework. Drumherum ist lediglich eine Event Based Component (EBC) gelegt. Die Komponente besteht aus der Input-Methode Process und dem Output-Event Result. Da das Bauteil für seine Arbeit zwei Angaben benötigt, den Pfad und das Suchmuster, werden diese zu einem Tuple<string, string> zusammengefasst. Dadurch hat die Process-Methode lediglich einen Parameter. Das ist wichtig, um Standardbausteine und Tooling verwenden zu können. In diesem Fall ist das zwar nicht relevant, aber es könnte sein, dass eine spätere Iteration den Einsatz von Standardbausteinen wie etwa Join sinnvoll erscheinen lässt. Daher ist es eine Tugend, mit nur einem Parameter zu arbeiten.
Um innerhalb der Methode zu erkennen, welche Bedeutung Item1 und Item2 des Tupels haben, weise ich beide jeweils an eine lokale Variable zu. So kann ein sprechender Bezeichner vergeben werden, aus dem sich die Bedeutung erschließt.
Listing 3
Dateinamen suchen.
public class Dateinamen_suchen { public void Process(Tuple<string, string> path_und_SearchPattern) { var path = path_und_SearchPattern.Item1; var searchPattern = path_und_SearchPattern.Item2; var filenames = Directory.EnumerateFiles(path, searchPattern, SearchOption.AllDirectories); Result(filenames); } public event Action< IEnumerable<string>> Result; }
Es ergibt sich nun die Frage, wie man das Bauteil automatisiert testen kann. Seine Aufgabe ist es, zu einem gegebenen Pfad und einem Suchmuster die Liste der gefundenen Dateinamen zu liefern. Folglich werden für einen automatisierten Test Testdaten benötigt. Diese habe ich im Testprojekt angelegt, wie Abbildung 3 zeigt.
[Abb. 3]
Testdaten zum automatisierten Testen der Dateisuche.
Ganz wichtig: Bei den Testdateien test1.txt, test2.txt et cetera muss die Eigenschaft Copy to Output Directory auf Copy always oder Copy if newer eingestellt werden. Dadurch werden die Testdateien samt Verzeichnisstruktur in das Ausgabeverzeichnis des Projektes kopiert. Im Test können die Dateien dann über den relativen Pfad testdaten angesprochen werden, wie Listing 4 zeigt. Wird im Verzeichnis testdaten nach den Dateien *.txt gesucht, müssen drei Dateinamen geliefert werden. Glücklicherweise liefert Directory.EnumerateFiles die Dateinamen als relative Namen. Wären es absolute Pfade, wäre eine Automatisierung schwieriger, da dann der absolute Pfad der jeweiligen Testumgebung zu berücksichtigen wäre.
Listing 4
Test: Dateinamen
[TestFixture] public class Dateinamen_suchen_Tests { private Dateinamen_suchen sut; private IEnumerable<string> result; [SetUp] public void Setup() { sut = new Dateinamen_suchen(); sut.Result += x => result = x; } [Test] public void Txt_Dateien_rekursiv_suchen() { sut.Process( new Tuple<string, string>( @"testdaten", "*.txt")); Assert.That(result.ToArray(), Is.EqualTo(new[] { @"testdaten\test1.txt", @"testdaten\test2.txt", @"testdaten\ebene2\test4.txt"