2013-07-25 19 views
5

Ich arbeite an einigen Test-Automatisierung für einen Dienst, und fand eine nette Möglichkeit, einige gemeinsame Setup-& Verifikation in eine "Sitzung" Klasse zu rollen.Wie kann ich überprüfen, ob bereits eine Ausnahme ausgelöst wurde?

Konzeptionell könnte ein Testfall wie folgt aussehen:

using (var managerSession = new Session(managerRole)) 
{ 
    // A manager puts some items in warehouse 
} 

using (var employeeSession = new Session(employeeRole)) 
{ 
    // An employee moves items from warehouse to store 
} 

using (var customerSession = new Session(customerRole)) 
{ 
    // A customer can buy items from the store 
} 

im Sitzungs Objektkonstruktor ich eine Verbindung mit dem Dienst einrichten ich mit der richtigen Authentifizierung pro Rolle usw. Testen bin, und in der Sitzung Entsorgen() Methode Ich habe einen gemeinsamen Validierungsblock, der zum Beispiel überprüft, dass während der Lebensdauer der Sitzung keine serverseitigen Fehler oder Warnungen aufgetreten sind.

Nun, das ist natürlich eine Art Missbrauch des IDispose-Musters, und wenn der Testcode in einem using-Block eine Ausnahme auslöst UND der Validierungsblock auch eine Ausnahme auslöst, maskiert die zweite Ausnahme die erste.

Konzeptionell wenn wir dieses Szenario haben:

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
} 

... und die Assertion fehlschlägt oder der Aufruf von managerSession.DoJob() löst eine Ausnahme aus, dann würde ich die Session Dispose() -Methode gerne überspringen sie den Validierungsblock, dh

public void Dispose() 
{ 
    if (NoExceptionThrown()) 
    { 
     Assert.IsFalse(this.serviceConnection.HasErrors(), "Service connection has errors"); 
    } 

    this.serviceConnection.Dispose(); 
} 

..., so dass die Testmethode versagt nie mit ‚Service-Anschluss hat Fehler‘, wenn er tatsächlich ausfällt mit ‚-Manager nicht seine Arbeit machen‘

Meine Frage ist: Ist es überhaupt möglich, die 'NoExceptionThrown()' Methode hier zu implementieren? Gibt es eine globale Eigenschaft, die überprüft werden kann oder die in Thread.CurrentThread versteckt ist, die verwendet werden könnte?

Update:

Meine Frage ist nicht wie diese :-) Refactoring

ich natürlich dieses Muster stattdessen verwenden könnte:

Session.ForRole(managerRole, (session) => { /* Test code here */ }); 

Mit der statischen Methode ForRole() definiert wie

public static void ForRole(Role r, Action<Session> code) 
{ 
    var session = new Session(r); 
    try 
    { 
     code(session); 
     Assert.IsFalse(session.serviceConnection.HasErrors()); 
    } 
    finally 
    { 
     session.Dispose(); 
    } 
} 

Aber ich bin neugierig, ob es einen Weg gibt, den Ausnahmezustand zu ergreifen, wie oben beschrieben.

+2

Zwei Dinge. Erstens, ja, das missbraucht "IDisposable". Verwenden Sie "IDisposable", um "Ich besitze eine nicht verwaltete Ressource, die so bald wie möglich freigegeben werden sollte". Wenn Sie etwas anderes bedeuten, wird Ihr Code schwer lesbar. Zweitens, sind Sie besorgt über * irgendeine * Ausnahme oder nur * nicht abgefangene * Ausnahmen? Angenommen, der Testcode löst eine Ausnahme aus, fängt sie ab und wird normal beendet. Sollte das markiert werden? –

+0

Ah, ich bin nur besorgt über _uncaught_ Ausnahmen. Ich werde die Frage aktualisieren ... – Christoffer

+0

Wie IDisposable missbrauchen: Ich bin eher besorgt über das Fehlen der gemeinsamen Validierung für jede Sitzung als die mögliche Maskierung von Fehlern, so dass diese Frage eher eine "nette zu haben" -Funktion ist. Die tatsächlichen Blöcke des Testcodes sind 10-100 Zeilen des UI-Automatisierungscodes, und wir haben bereits erkannt, dass Fehler unerkannt bleiben, weil einer der Validierungsschritte in einem der Blöcke verpasst wurde (oder im falschen Block gemeldet wurde). – Christoffer

Antwort

1

Es wäre hilfreich gewesen, wenn es eine Überlastung der IDisposable.Dispose ist die Exception einen Parameter vom Typ nahm, um anzuzeigen, welche Ausnahme, falls vorhanden, wurde in einem finally Zusammenhang mit seiner Bereinigung im Zusammenhang anhängig.Während eine Dispose Methode im Allgemeinen die Besonderheiten der Ausnahme nicht interessieren sollte, können Bedingungen während der Dispose Methode entstehen, die dem Anrufer gemeldet werden sollte. Jede Ausnahme, die von Dispose ausgelöst wird, ersetzt jede Ausnahme, die im Kontext des Aufrufers finally war, so dass es hilfreich wäre, wenn eine Dispose Methode eine ausstehende Ausnahme kapseln könnte, bevor sie ersetzt wird. Leider existiert kein solches Feature und ich erwarte nicht, dass irgendwelche hinzugefügt werden.

Während einige Hacks verwendet werden können, um etwas wie den gewünschten Effekt zu erreichen, ist die einzige semantisch korrekte Methode, dass die Ausnahme ein Parameter für eine Dispose Methode ist. Das Problem bei jedem anderen Ansatz besteht darin, dass ein Dispose aus mehreren verschachtelten finally Blöcken ausgeführt werden kann, von denen einige ausstehende Ausnahmen haben und einige nicht; Code, der den Ausführungskontext untersucht, um den Status des am tiefsten verschachtelten Blocks finally zu bestimmen, kann fehlschlagen, wenn dieser Block nicht derjenige ist, der die Lebensdauer des zu entsorgenden Objekts schützt.

+0

Ich denke, ich werde diese Antwort als die korrekteste akzeptieren – Christoffer

0

Nun, eine sichere, aber hässliche Art, es zu tun, ist eine bool (default false) in Ihrer Klasse zu haben.

Ich glaube nicht, dass Sie viel sauberer als das mit Ihrem IDisposable-Muster bekommen werden.

In diesem Fall könnte ein Versuch ... catch ... schließlich besser funktionieren, da Sie direkten Zugriff auf das Ausnahmeobjekt haben würden, das Sie auf Null-Ness testen können (ist das ein Wort?) Und möglicherweise Speichern Sie es sogar für den späteren Gebrauch. Sie sollten nichts verlieren, denn using ist nur Zucker für einen Versuch, endlich zu fangen.

+1

Ja, Nullheit ist ein perfektes Wort. – Christoffer

+0

Und für eine ernstere Bemerkung, ist das Einstellen einer Eigenschaft, die den Validierungsblock in der Dispose-Methode steuert, eigentlich keine so gute Idee. Wenn wir sowieso etwas auf jedem using-Block hinzufügen, wäre es besser, den vorhandenen Validierungscode auf eine andere Methode umzuformen und einfach vor dem Schließen des Bereichs aufzurufen. – Christoffer

+0

@Christoffer Yeah, ich glaube, du versuchst es Round-Plug-in-ein-Quadrat-Loch-Sache mit Verwendung. Wenn Supercat darauf hinweist, besteht der richtige Weg darin, das Exception-Objekt zu übergeben oder anzugeben, ob eine Ausnahme aufgetreten ist. Also, ich denke, Sie könnten die passende Methode hinzufügen, einfach die Verwendung ablegen und Dispose (Ausnahme) selbst aufrufen? Es gibt da auch Probleme, und ich denke nicht, dass du die Sprache zwingen kannst, genau das zu tun, was du willst, ohne es zu entkernen und den Kopf wieder zu befestigen: c. Und soweit ich weiß, gibt es keine Möglichkeit, außerhalb eines Catch-Blocks nach einer Ausnahme zu suchen. – Xcelled194

Verwandte Themen