2016-06-22 22 views
1

Ich habe eine benutzerdefinierte Assertion, die immer eine Ausnahme innerhalb davon auslöst, aber sie wird in einer C# -Funktion verwendet, die einen Rückgabewert erfordert. Im folgenden Beispiel löst CustomAssert.Fail() immer eine Ausnahme aus, und daher wird "null zurückgeben" niemals ausgeführt. Code Coverage markiert dies als ungeprüft, und ich möchte das umgehen.C# -Code-Coverage kann die erforderliche Rückgabe nicht mit einem benutzerdefinierten Assertionsfehler erreichen

public string GetSomething() 
{ 
    CustomAssert.Fail(); 
    return null; 
} 

Ich habe darüber nachgedacht, CustomAssert.Fail Refactoring() ein Null-Objekt zurück und so etwas wie dies zu tun, aber es scheint ein bisschen hackish. Gibt es eine andere Möglichkeit, dies zu erreichen, oder muss ich die Codeabdeckung opfern?

public string GetSomething() 
{ 
    return CustomAssert.Fail() as string; 
} 
+0

Wenn die Funktion aufgrund der Assertion immer fehlschlägt, warum markieren Sie sie nicht einfach als veraltet? Wenn es nur ein bestimmter Codepfad ist, warum werfen Sie nicht einfach eine 'NotSupportedException' oder ähnliches? – InBetween

+0

Diese Funktion ist nur ein Beispiel für viele Orte, an denen dies verwendet wird. Dies ist eine Ausnahme, aber es gibt viele verwandte Aufrufe, die dieser CustomAssert-Helper unterstützt. Siehe die Assert-Klasse von Microsoft: https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assert.aspx –

+0

Ich verstehe nicht. Ihr Problem, wie in Ihrer Frage beschrieben, ist, dass Ihre Testfälle nicht die Rückgabe treffen, weil die Behauptung * immer * fehlschlägt. Wenn unter bestimmten Bedingungen die Assert nicht fehlschlagen darf, dann werden Ihre Tests nicht alle möglichen Ausführungspfade ausreichend abdecken, da Sie nie die Return-Anweisung erreichen. Wenn andererseits dieser bestimmte Code-Pfad immer fehlschlagen muss, dann werfen Sie einfach eine Ausnahme und führen Sie keine Assertion oder Returns aus. Ich sehe hier keine dritte Möglichkeit. – InBetween

Antwort

0

Zunächst einmal würde ich Code Coverage nicht als die wichtigste Metrik im Test betrachten. Dies ist ein perfektes Beispiel, bei dem es offensichtlich ist, dass alles perfekt getestet werden kann und immer noch nicht 100% abgedeckt wird. Ich würde damit leben, dass ich in diesem Fall keine vollständige Berichterstattung habe.

Das heißt, ein Weg, um das Problem CustomAssert.Fail() ist Refactoring ein Exception zurückzukehren und dann einfach schreiben:

public string GetSomething() 
{ 
    throw CustomAssert.Fail(); 
} 

Nachteile? Ihr CustomAssert wird inkonsistentes Verhalten haben, das sollte wenn möglich vermieden werden. Wie Sie gut in Kommentaren sagen, können bedingte Behauptungen aus offensichtlichen Gründen keine Ausnahme zurückgeben, so dass Sie CustomAssert.IsNotNull(...) nichts zurückgeben und werfen, wenn die Assert fehlschlägt, während CustomAssert.Fail() eine Ausnahme zurückgibt, die explizit vom Verbraucher ausgelöst werden muss. Die Lösung scheint ein wenig yucky.

Eine Möglichkeit, diese Unannehmlichkeiten leicht zu verbessern, CustomAssert die folgende Art und Weise, Refactoring ist:

public static class CustomAssert 
{ 
    public static void IsNotNull<T>(this T target) 
    { 
     if (ReferenceEquals(target, null)) throw new ArgumentNullException(); 
    } 

    public static void IsTrue<T>(this T target, Predicate<T> validator) 
    { 
     if (!validator(target)) throw new ArgumentException(); 
    } 

    public static void IsInRange<T, Q>(this T target, Q inclusiveLowerBound, Q exclusiveUpperBound) where T: IComparable<Q> 
    { 
     ... 
    } 

    //etc. 

    public static T Fail<T>() where T :Exception, new() 
    { 
     return new T(); 
    } 
} 

Nun ist die Verwendung unterschiedlich für Fail und jede bedingte Behauptung und die Inkonsistenz wird etwas aufgelöst:

public void Foo(Bar arg) 
{ 
     //Conditional usage 
     arg.IsNotNull(); 
     arg.IsNotTrue(t => t != null); 
     arg.IsInRange(0, 2); 

     //Unconditional fail 
     throw CustomAssert.Fail<NotSupportedException>(); 
} 

Alles was gesagt wird, würde ich ernsthaft erwägen, den Namen CustomAssert zu ändern. Assert hat eine ziemlich etablierte Bedeutung für die meisten Programmierer und kann zu Missverständnissen führen. Vielleicht wäre etwas ähnliches wie CustomValidator eine bessere Idee.

+0

Es heißt eigentlich nicht CustomAssert, ich habe diesen Namen nur als Beispiel benutzt, und es ist zugegebenermaßen keine gute Wahl. Außerdem stimme ich zu, dass die Codeabdeckung keine perfekte (oder auch nur eine gute) Metrik für gut getesteten Code ist, aber ich versuche immer noch, Wege zu finden, um ihre Nützlichkeit zu verbessern. Wenn es viele Lücken wie die in meiner Frage gibt, macht das Code-Coverage weniger nützlich, da ich ständig die Orte überprüfen muss, an denen es fehlt, und die gute Begründung dafür zu überprüfen. –