Archiv der Kategorie: Tests

NCover: Attribute-Based Type Exclusion, but the wrong way round…

With Version 1.5.2, NCover introduced a Attribute-Based Type Exclusion. It works, but not as I expected.

I normally use NCover together with my test code. When I have a class to test that throws an exception the test function is not covered completely.
Code Coverage without excluded Attribute
The function BarTest() is only covered to 67% as the end of the function is not executed because the Exception was thrown. I was waiting for the possibility to define that a function does not need to be covered with adding an attribute to the Function. But when I add an Attribute to the function and define this Attribute to be excluded (with //ea AttributeName), the Function is not covered.
Code Coverage with excluded Attribute
So instead of having a higher code coverage I have a lower code coverage. Not the result I was expecting from this feature.
But maybe this will change in the future. I keep watching…

Code Coverage mit NCover und NCoverExplorer

Grant Drake hat sein Tool NCoverExplorer vorgestellt. NCoverExplorer ist ein Tool, um die Reports von NCover komfortabel zu begutachten.Wer NCoverBrowser von Jeff Key kennt wird sich damit sofort zurechtfinden, da NCoverExplorer nach dem Vorbild von NCoverBrowser erstellt wurde. Grant betrieb diesen Aufwand, da der Sourcecode von NCoverBrowser nicht frei verfügbar ist (wegen komerzieller Komponenten, die eingesetzt wurden).
NCoverExplorer wird mit TestDriven.NET ausgeliefert, benötigt aber noch NCover. Dann kann aber direkt aus der Entwicklungsumgebung (auch aus Visual C# Express Edition) der Coverage Report geöffnet werden:
Code Coverage mit TestDriven.NET

Fallstricke bei NMock mit Klassen

Mit NMock können Attrappen (Mock Objetcs) für Klassen und Interfaces erzeugt werden. Ein deutscher Artikel über NMock ist beim dot.net magazin online abrufbar. Falls Mock Objects für Klassen erstellt werden, müssen einige Dinge beachtet werden.

1. Funktionen und Properties müssen virtual sein
Funktionen und Properties, welche durch das Mock Object ersetzt werden sollen, müssen als

virtual

deklariert werden, da NMock diese sonst nicht überschreiben kann.
NMock wirft normalerweise eine Exception, falls man eine Funktion mit

Expect()

,

ExpectAndReturn()

,

ExpectAndThrow()

oder

ExpectNoCall()

konfiguriert und diese nicht virtual ist.
Wenn aber ein Property nicht als

virtual

deklariert wird und mit

SetupResult()

das Verhalten überschrieben werden soll, wird keine Exception generiert. Es wird aber beim Aufrufen des Properties der Code der zu ersetzenden Klasse aufgerufen:

public class ClassToMock
{
public string Bar
{
get { return "bar"; }
}
}
[TestFixture]
public class TestingClass
{
[Test]
public void MockTest()
{
DynamicMock mock = new DynamicMock(typeof(ClassToMock));
mock.SetupResult("Bar", "foo");
ClassToMock c = (ClassToMock)mock.MockInstance;
Assert.AreEqual("foo", c.Bar);
}
}

Dieser Test schlägt Fehl, da immer noch der Code der Klasse

ClassToMock

aufgerufen wird und somit der Text „bar“ und nicht der Text „foo“, wie eigentlich erwartet, zurückgegeben wird. Sobald das Property als

virtual

deklariert wird, kann der Test erfolgreich ausgeführt werden.

Nicht virtuelle Funktionen können auch nicht durch den „Strict“ Mechanismus überwacht werden. Folgender Test sollte eigentlich fehlschlagen, da es nicht erwartet wird, dass die Funktion

Foo()

aufgerufen wird (kein

Expect...()

). Der Test wird aber erfolgreich ausgeführt.

public class ClassToMock
{
public void Foo() {}
}
[TestFixture]
public class TestingClass
{
[Test]
public void MockTest()
{
DynamicMock mock = new DynamicMock(typeof(ClassToMock));
mock.Strict = true;
ClassToMock c = (ClassToMock)mock.MockInstance;
c.Foo();
mock.Verify();
}
}

Sobald man Foo als

virtual

deklariert schlägt der Test wie erwartet fehl.

2. Wenn Strict benutzt wird muss Finalize als expected angegeben werden
Durch setzten des Attributes

Strict

auf

true

wird NMock angewiesen, dass alle Funktionsaufrufe vorher angemeldet werden müssen. Das gilt auch für den Destruktor, der am Ende der Lebenszeit des Objekts aufgerufen wird.
Da der Destruktor (Methode

Finalize()

) durch den Garbage Collector aufgerufen wird hat man keine Kontrolle darüber, wann der Destruktor aufgerufen wird. Bei den Tests wird er normalerweise nach den eigentlichen Tests aufgerufen. Deshalb wird eine fehlende Finalize-Anmeldung auch nicht als fehlschlagender Test gewertet, es wird aber eine Fehlermeldung auf die Error-Konsole ausgegeben, was nicht sehr Vertrauenserweckend wirkt.
Wenn man die Tests mit NUnit-GUI oder mit dem Visual-Studio-PlugIn TestDriven.NET ausführt ist diese Fehlermeldung nicht sichtbar.
Folgender Code erzeugt die Fehlermeldung:

public class ClassToMock
{
}
[TestFixture]
public class TestingClass
{
[Test]
public void MockTest()
{
DynamicMock mock = new DynamicMock(typeof(ClassToMock));
mock.Strict = true;
ClassToMock c = (ClassToMock)mock.MockInstance;
mock.Verify();
}
}

Wenn der Test mit nunit-console aufgerufen wird, wird am Schluss folgende Fehlermeldung ausgegeben:

Unbehandelte Ausnahme: NMock.VerifyException: Finalize() called too many times
expected:0
but was:<1>
at NMock.Mock.Invoke(String methodName, Object[] args)
at ProxyClassToMock.Finalize()

Wenn man nun aber am Anfang des Codes folgende Zeile einfügt:

mock.Expect("Finalize");

reklamiert die Funktion

Verify()

zu Recht, da der Destruktor zu diesem Zeitpunkt noch nicht aufgerufen wurde.
Man kann die oben angegebene Zeile aber nach den letzten

Verify()

-Aufruf setzten. Dadurch wird das Mock Object auf den Destruktor vorbereitet, welcher dann am Ende des Testes aufgerufen wird. Dieser Code kann z.B. in den

[TearDown]

-Bereich eines Testes geschrieben werden.

Owen Rogers, auch bekannt unter dem Namen exortech, hat diesen Bug auch entdeckt und in seinem Blog beschrieben. Scheinbar hat aber diese Änderung den Weg in den Code von NMock nicht gefunden…