Laden...

Sollte man bei hinzugefügten IOExceptions auch passende Unit Tests implementieren?

Erstellt von Renão vor 7 Jahren Letzter Beitrag vor 7 Jahren 2.300 Views
R
Renão Themenstarter:in
9 Beiträge seit 2017
vor 7 Jahren
Sollte man bei hinzugefügten IOExceptions auch passende Unit Tests implementieren?

Hallo zusammen,

dies ist mein erster Post hier, daher zerreisst mich nicht gleich, wenn ich hier evtl. im falschen Forum mit meinem Anliegen gelandet bin 😉.

Ich habe seit längerer Zeit mal wieder mit IO zu tun und bin es gewohnt, bei jeder Code-Änderung immer einen Unit-Test hinzuzufügen.

Nun habe ich im Rahmen eines Datei-Downloaders einer Unity-App ein Exception Handling für IOExceptions um einen FileStream hinzugefügt. Aus Gewohnheit habe ich nun auch den Drang einen Test hinzuzufügen, da es bei mir auch eher ein "Fire-and-forget"-Fix ist und ich mich über den Test auch gerne in (falscher) Sicherheit wiegen möchte.

Daher würde es mich interessieren, ob ihr denkt, dass es generell sinnvoll wäre dieses Verhalten zu testen und wie ihr das anstellen würdet.

Über eine rege Diskussion oder einen Hinweis, wo dieses Thema ggf. schon mal behandelt wurde, würde ich mich freuen.

Besten Dank!

T
2.224 Beiträge seit 2008
vor 7 Jahren

Ich hätte für deinen Wunsch, für ein spezifisches Problem eine allgemeine Lösung zu bekommen, keine brauchbare Anweisung,
Der Unit Test ist ja dazu da, zu prüfen ob deine Logik funktioniert.
Du willst aber nun, dass deine Logik vorsätzlich scheitert, was nur bedeutet, dass dein Unit Test in einen gewollten Fehlerfall rennt.

Dies zu provozieren, macht nur Sinn wenn du diesen Fall gesondert beachten müsstest.
Hier kannst du ggf. auf eine nicht vorhandene Datei als Quelle/Ziel hinweisen.
Wie dies umgesetzt wird, hängt aber an deinem Code.

Ansonsten ist das Problem aktuell für deinen Fall zu spezifisch, als das eine allgemeine Lösung geliefert werden kann.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

D
985 Beiträge seit 2014
vor 7 Jahren

Dein Ansatz - so wie ich ihn verstanden habe - ist halt schwer testbar.

Du kannst eigentlich nur zuverlässig den Erfolgsfall testen (vor allem, weil es eben kein Unit-Test sondern ein Integration-Test ist), alle anderen Fehlerfälle müsstest du umständlich produzieren und du kannst nicht wissen, ob diese provozierten Fehler nur Seiteneffekte darstellen und die auf einmal doch funktionieren.

Du testest den Fehlerfall, dass der Dateipfad nicht vorhanden ist mit der Dateiangabe Z:\Foo\MyData.dat. Das Laufwerk und somit auch das Verzeichnis existiert auf deinem Rechner nicht und provoziert somit ganz wunderbar einen Fehler, der ja auch vom Test erwartet wird und somit ist der Test erfolgreich.

Ein anderer Entwickler lässt den Test laufen und der Test fällt durch, weil der Pfad Z:\Foo\ dort existiert und eine Datei angelegt werden kann.

Wenn wir diesen Datei-Downloder mal sezieren und auf das Wesentliche reduzieren, dann haben wir etwas, dass einen Stream von A nach B transportiert.

Dazu braucht das Konstrukt etwas, wo es einen Stream bekommt und wo es den Stream wieder abladen kann. Das könnte man (ganz grob skizziert) wie folgt schreiben:


public class StreamMover
{
    public StreamMover( IStreamReadStore readStore, IStreamWriteStore writeStore )

    public async Task ProcessAsync( string identifier )
    {
        var reader = _readStore.GetReader( identifier );
        var data = await reader.ReadAsync();
        var writer = _writeStore.GetWriter( identifier );
        await warier.WriteAsync( data );
    }
}

Dieses Konstrukt kann man jetzt ganz hervorragend auch hinsichtlich der Fehlerfälle tsten, weil man die beiden Komponenten mocken kann und dort einfach so eine Exception wirft.

16.835 Beiträge seit 2008
vor 7 Jahren

.. das ist eigentlich auch schon der Punkt.
Du willst einen Integrationstest und keinen Unittest.

Ein Test ist nur dann ein Test, wenn er dauerhaft ein immer wiederkehrendes Szenario gewährleistet.
Willst Du bewusst Exceptions werfen, dann musst Du zB. mit Shims oder einem entsprechenden Mock diese Exception aktiv auslösen.

P
1.090 Beiträge seit 2011
vor 7 Jahren

I
Der Unit Test ist ja dazu da, zu prüfen ob deine Logik funktioniert.
Du willst aber nun, dass deine Logik vorsätzlich scheitert, was nur bedeutet, dass dein Unit Test in einen gewollten Fehlerfall rennt.

Ist bei der Frage vielleicht nicht der ganz die richtige Anmerkung. Aber zu testen das Etwas funktioniert, ist ein sogenannter positiv Test. Was aber schon mal gut ist.
Das stellt aber meistens kein Problem da, auf konkrete Anforderungen, können die meisten Entwickler eine konkrete Lösung bieten.
Was man meines Erachtens nicht aus den Augen lassen sollte sind negative Tests. Also wenn der DAU misst eingibt. (Kennen wir alle)

Grundlegend ist hier ein Umdenken notwendig.
In der 1. Phase Schreibe ich Software, damit sie bei dem Kunden funktioniert.
In der 2. Phase überlege ich mir wie ich sie zu Fehlern/Absturz bringen kann.
Und beides Teste ich.

Zu Renão.
Wie schon vorher von anderen erwähnt, schreibst du keinen Unit Test sondern einen Integrations-Test. Die Frage ist ob es den Aufwand wert ist.
Meines erachten gibt es da keine Pauschale Aussage ob es richtig oder Falsch ist. Du (oder dein Chef) musst wissen wie wichtig die Funktionalität für den Kunden ist. Und ob es sich lohnt dafür einen Test zu schreibe.

Grundlegend finde ich aber dein Vorgehen gut. Wenn der Kunde einen Fehler meldet, schreibe ich einen Test dafür. Sollte so sein.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

R
Renão Themenstarter:in
9 Beiträge seit 2017
vor 7 Jahren

Hallo zusammen,

vielen Dank für euer zahlreiches und detailliertes Feedback.

Aktuell ist das größte Problem, dass es im Unity Kontext gerade einmal eine vernünftige Infrastruktur gibt, die Unit-Tests erlaubt und dadurch viele Komponenten aus der UnityEngine.dll nicht in den Tests zur Verfügung stehen bzw. crashen.

Generell bin ich ein großer Freund von Integrationtests, da sie im Grunde auch vielmehr den Sachverhalt und im Idealfall eine Art Use-Case abbilden und somit auch eine Form der (ergänzenden) Dokumentation darstellen.

Ich bemerke an dieser Stelle, dass sich bei mir in der Zwischenzeit auch immer mehr grundlegende Fragen ergeben, wie bspw. "Wie weit passe ich meinen Code für eine bessere Testbarkeit an?".

Bis dato fahre ich eine Lösung, die die kritischen Punkte größtmöglich isoliert und es im Grunde nur einen Punkt gibt, bei dem die IOException gecatcht wird und innerhalb dieses try-Blocks baut sich dann ein wenig Struktur nach unten hin auf (es geht im Grunde nur um das Herunterladen und Wegspeichern von Daten). Im Grunde möchte ich eigentlich nur absichern, dass bei einer IOException ein besonderes Verhalten ausgelöst wird.

Ich denke durch den eingeschränkten Unity-Test-Kontext werde ich aber erstmal die Stelle einmalig manuell durchtesten und den Code ansonsten bisweilen als 'worksforme' abhaken.

D
985 Beiträge seit 2014
vor 7 Jahren

Ein Integrations-Test ist ja auch nicht unsinnig, aber eben kein Unit-Test.

Bei einem Integrations-Test muss die Infrastruktur vorhanden sein -> der kann fehlschlagen, weil die Infrastruktur einen Fehler hat (z.B. der Download-Server ist nicht erreichbar, die Zugangsdaten sind falsch, das Laufwerk steht nicht zur Verfügung, ...).

Ein Unit-Test kommt ohne irgendwelche Infrastruktur aus (weil diese ja mit einem Mock simuliert wird) -> kann also immer laufen.

Für einen Integrations-Test muss man nicht wirklich etwas berücksichtigen, für einen Unit-Test muss die Infrastruktur mockbar sein - stellt also höhere Anforderung an das Design.

Aus diesem Grund sind Integrations-Tests beliebter als Unit-Tests, bzw. werden Integrations-Tests auch gerne mal als Unit-Tests verkauft 😉

R
Renão Themenstarter:in
9 Beiträge seit 2017
vor 7 Jahren

Ja, das verstehe ich. Wenn ich Software für den Server geschrieben habe, war es für mich auch häufig einfacher einen Integrationtest zu schreiben, als jetzt im Client. Zumindest wenn es so nah ans System geht.

Mometan ist das Design so, dass es eine IDownloader Schnittstelle gibt, die im Unity-Client durch einen UnityDownloader bestückt wird, in dem aus Gründen auf Unity Coroutinen zurückgegriffen werden müssen, die sich nicht noch gut extrahieren lassen würden bzw. gemessen am letztendlichen Zweck innerhalb der Anwendung, könnte dies am Ende sogar 'overengineered' wirken.

Da ich über den Zwischenschritt Unity mehr oder weniger Quereinsteiger in C# bin, würde mich natürlich interessieren, ob und welche Tipps ihr ggf. für's Testen 'normaler' Desktop-Anwendungen geben würdet.

Letzten Endes werde ich arbeitstechnisch weiterhin bei meinem Windows-Rechner bleiben, sodass ich mein Tooling weitesgehend in C# aufbauen möchte, da ich die Sprache sehr interessant finde und die Möglichkeiten im .net-Framework wirken aktuell sehr interessant auf mich.

Vielleicht habt ihr ja noch weitere Tipps, die den Beitrag über Unit-Tests von 2013 hier im Forum ergänzen - zum Beispiel, wie ihr eure Integrationtests schreibt oder wie es sich mit weiteren Tools zur Testabdeckung, Profiling etc. verhält.

Auch über Hinweise zu weiteren lesenswerte Beiträge hier im Forum würde ich mich sehr freuen, nur ehrlicherweise ist die Informationsfülle in dieser Community schon ein großes Brett, wenn man hier neu ist 😉.

16.835 Beiträge seit 2008
vor 7 Jahren

Unit Tests sind strukturell nicht anders als Integrationstests; sind halt keine Mocks, die genutzt werden, sondern konkrete Implementierungen.

Nicht für ungut, aber wie ich Dir im anderen Thread schon geschrieben hab, solltest Du evtl. einfach auch nen bisschen Zeit in die eigenen Basics investieren, statt Dir das nur hier mit Bitten auf dem Präsentierteller geben zu lassen 😉
Ein gut investiertes Wochenende in die Virtual Academy und Pluralsight (3 Monate kostenlos über Visual Studio Dev Essentials) bringen Dir viel mehr, als 200 Fragen 😉

R
Renão Themenstarter:in
9 Beiträge seit 2017
vor 7 Jahren

Danke für den Tipp - da haben sich die Fragen doch dahingehend zumindest schon einmal gelohnt 😉

Hinweis von Abt vor 7 Jahren

Bitte keine Fullquotes
[Hinweis] Wie poste ich richtig?