Ich schreibe eine Multithread-Anwendung und versuche herauszufinden, wie man Komponententests dafür schreiben kann. Ich denke, das ist wahrscheinlich eine andere Frage, wie man das am besten macht. Jedenfalls habe ich eine Klasse wie die folgende, die weiß, dass sie nicht threadsicher ist und sie in einem Komponententest beweisen will, aber nicht herausfinden kann, wie man es macht:
%Vor%Der Beweis, dass etwas threadsicher ist, ist schwierig - wahrscheinlich haltend - schwierig. Sie können zeigen, dass eine Race-Bedingung einfach zu produzieren ist oder dass sie schwer zu produzieren ist. Aber keine Race Condition zu produzieren bedeutet nicht, dass es nicht da ist.
Aber: mein üblicher Ansatz hier (wenn ich Grund habe, ein wenig Code zu denken, der threadsicher sein sollte, ist nicht), ist es, viele Threads hochzufahren, die hinter einem einzigen ManualResetEvent warten. Der letzte Thread, der zum Gate gelangt (mit Interlocked zum Zählen), ist dafür verantwortlich, das Gate zu öffnen, so dass alle Threads gleichzeitig auf das System treffen (und bereits existieren). Dann machen sie die Arbeit und prüfen, ob vernünftige Ausgangsbedingungen herrschen. Dann wiederhole ich diesen Vorgang sehr oft. Dies ist normalerweise ausreichend, um eine vermutete Fadenrasse zu reproduzieren und zu zeigen, dass sie sich von "offensichtlich gebrochen" zu "nicht offensichtlich gebrochen" bewegt (was wesentlich anders ist als "nicht gebrochen").
Beachten Sie auch: Der meiste Code muss nicht threadsicher sein.
Ich schreibe häufig Komponententests, um zu beweisen, dass einige Codes threadsicher sind. Normalerweise schreibe ich diese Tests als Reaktion auf einen in der Produktion gefundenen Fehler. In diesem Fall ist der Zweck des Tests der Nachweis, dass der Fehler repliziert wurde (Test fehlschlägt) und dass der neue Code das Threading-Problem (Testdurchläufe) behebt und dann als Regressionstest für zukünftige Versionen fungiert.
Die meisten Tests mit Thread-Sicherheitstests, die ich geschrieben habe, testen eine Thread-Race-Bedingung, aber einige testen auch Thread-Deadlocks.
Proaktiv ist es ein bisschen schwieriger, den Code zu testen, der ist thread safe. Nicht, weil der Komponententest schwieriger zu schreiben ist, sondern weil Sie eine solide Analyse durchführen müssen, um zu ermitteln, was Threads unsicher sein könnten. Wenn Ihre Analyse korrekt ist, sollten Sie in der Lage sein, einen Test zu schreiben, der fehlschlägt, bis Sie den Code-Thread sicher machen.
Beim Test auf eine Thread-Race-Bedingung folgen meine Tests fast immer dem gleichen Muster: (Dies ist Pseudocode)
%Vor%Gewindesicherheit kann nicht zuverlässig getestet werden, weil es von Natur aus nicht deterministisch ist. Sie könnten versuchen, die gleiche Operation ein paar hundert Mal parallel in verschiedenen Threads auszuführen und zu sehen, ob die Ergebnisse am Ende konsistent sind. Nicht wirklich toll, aber besser als nichts, nehme ich an.
Ich habe mit Unit-Tests aufgegeben, um Threading-Probleme zu erkennen. Ich benutze nur einen Systemlasttest mit einer ganzen Reihe von Hardware, (wenn es Hardware gibt - oft mit meinen Jobs gibt es uControllers in Netzwerken), und eine unverhältnismäßig große Anzahl von automatisierten Clients läuft flat-out. Ich lasse es für eine Woche laufen, während ich andere Sachen mache. Am Ende der Woche nehme ich die Ladung ab und überprüfe, was übrig ist. Wenn es noch funktioniert, sind keine Objekte geleakt und der Speicher hat nicht merklich zugenommen, ich versende es.
Das ist so viel Qualität, wie ich mir leisten kann :)
Tags und Links .net c# unit-testing multithreading