Ist die Definition TestMethod im test Basis-Klassen nicht unterstützt, MsTest?
Diese Frage betrifft ein Allgemeines unit-test-Technik mit potentiell sehr nützlich Breite Palette von Szenarien anwendbar. Aber es ist leichter zu verstehen mit einem Beispiel zu illustrieren meine Frage besser.
Sagen wir, ich will, um zu testen, dass alle Typen, überschreiben Equals()
nicht so richtig. Da Equals()
ist definiert als virtuelle System.Object
eine große Auswahl an Typen können sich ändern, das Verhalten. Jeder Typ, der das tut, wird haben tests, um sicherzustellen, dass das neue Verhalten folgt die implizite Erwartungen an einen Aufrufer dieser Methode. Speziell für Equals()
, wenn Sie überschreiben diese Methode mit der neuen Implementierung muss sicherstellen, dass zwei gleiche Objekte müssen gleiche hash-codes, definiert durch System.Object.GetHashCode()
.
Damit zu erzwingen, mehrere test-Klassen benötigt werden, und Sie werden alle test für die gleiche Konsistenz von Verhalten über alle diese Typen.
Zu vermeiden, re-geben Sie alle TestMethods erforderlich, um zu testen, wie Typ-I-stattdessen definieren Sie eine Basis-test-Klasse, die sieht aus wie unten, und haben diese test-Klassen Erben alle das gleiche Verhalten test-suite:
///<summary>
///Test fixture base class for testing types that overrides Object.Equals()
///</summary>
///<typeparam name="T">The production type under test</typeparam>
public abstract class EqualsFixtureBase<T>
{
#region Equals tests
protected static void CompareInstances(T inst1, T inst2, bool expectedEquals)
{
Assert.AreEqual(expectedEquals, inst1.Equals((T)inst2));
Assert.AreEqual(expectedEquals, inst1.Equals((object)inst2));
if (expectedEquals)
{
//equal instances MUST have identical hash codes
//this is a part of the .NET Equals contract
Assert.AreEqual(inst1.GetHashCode(), inst2.GetHashCode());
}
else
{
if (inst2 != null)
{
Assert.AreNotEqual(inst1.GetHashCode(), inst2.GetHashCode());
}
}
}
///<summary>
///Creates version 1 instance of the type under test, not 'Equal' to instance 2.
///</summary>
///<returns>An instance created with properties 1.</returns>
protected abstract T CreateInstance1();
///<summary>
///Creates version 2 instance of the type under test, not 'Equal' to instance 1.
///</summary>
///<returns>An instance created with properties 2.</returns>
protected abstract T CreateInstance2();
///<summary>
///Creates an instance equal to the version 1 instance, but not the identical
///same object.
///</summary>
///<returns>An instance created with properties equal to instance 1.</returns>
protected abstract T CreateInstanceThatEqualsInstance1();
[TestMethod]
public void Equals_NullOrDefaultValueTypeInstance()
{
T instance = CreateInstance1();
CompareInstances(instance, default(T), false);
}
[TestMethod]
public void Equals_InstanceOfAnotherType()
{
T instance = CreateInstance1();
Assert.IsFalse(instance.Equals(new object()));
}
[TestMethod]
public void Equals_SameInstance()
{
T slot1 = CreateInstance1();
CompareInstances(slot1, slot1, true);
}
[TestMethod]
public void Equals_EqualInstances()
{
T slot1 = CreateInstance1();
T slot2 = CreateInstanceThatEqualsInstance1();
CompareInstances(slot1, slot2, true);
CompareInstances(slot2, slot1, true);
}
[TestMethod]
public void Equals_NonEqualInstances()
{
T slot1 = CreateInstance1();
T slot2 = CreateInstance2();
CompareInstances(slot1, slot2, false);
CompareInstances(slot2, slot1, false);
}
#endregion Equals tests
}
Kann ich dann wiederverwenden, diese TestMethods für jeden Typ überschreiben von Equals(). Zum Beispiel, das wäre der test-Klasse definition für die Prüfung, dass die System.String
Typ implementiert Equals()
richtig.
[TestClass]
public class ExampleOfAnEqualsTestFixture : EqualsFixtureBase<string>
{
[TestMethod]
public void Foo()
{
Assert.IsTrue(true);
}
protected override string CreateInstance1()
{
return "FirstString";
}
protected override string CreateInstance2()
{
return "SecondString";
}
protected override string CreateInstanceThatEqualsInstance1()
{
return "FirstString";
}
}
Diese können auch erweitert werden. Zum Beispiel für Arten, die überlastung der == und != die Betreiber, eine zweite abstrakte test-Basisklasse definiert werden kann (D. H. EqualsOperatorsFixtureBase<T> : EqualsFixtureBase<T>
), dass tests, die die Implementierung dieser Operatoren sind nicht nur korrekt, sondern auch im Einklang mit den erweiterten Definitionen von Equals()
und GetHashCode()
.
Kann ich dies tun, mit NUnit, aber wenn mit MsTest ich Probleme.
a) nur Visual Studio 2010 entdeckt die Foo()
test-Methode, nicht die geerbten Methoden testen, so kann er Sie nicht ausführen. Es scheint, die Visual Studio-test-loader nicht gehen die Vererbungshierarchie der test-Klasse.
b) Wenn ich diese Typen in TFS, TFS findet die abstrakte EqualsFixtureBase geben und denkt, es ist eine test-Klasse ausgeführt werden. Aber da es nicht erstellt werden kann, kann es nicht starten Sie es und Bezeichnungen der tests in dieser Art als nicht schlüssig -, die den test nicht ausführen, und so das bauen (!).
Gibt es eine Möglichkeit, dies zu umgehen, oder ist das eine Einschränkung von MsTest und Visual Studio?
Wenn dem so ist, ist die Festsetzung dieser in der roadmap für VS/TFS ??
Wäre dies sehr nützlich, vor allem beim testen von Produktionsarten, die eine Schnittstelle implementieren, oder sind Teil einer erbschaft hierarcy, wo bestimmte Mitglieder semantischen 'Vertragsart' Invarianten Eigenschaften oder - wenn das Sinn macht.
Grundsätzlich nicht mit Unterstützung für das hemmt mich von refactoring mein test-code zu entfernen Vervielfältigung.
Dank
EDIT: ich fand dieser link zu einem der MSDN-blogs, es sagt der folgende
"In Whidbey, Unterstützung für test-Klasse Vererbung fehlte. In Nunit, es wird vollständig unterstützt. Diese beseitigt werden Orcas".
Geschrieben wurde, vor über drei Jahren. Warum hat Sie diese nicht Hinzugefügt worden noch? Ich verstehe es nicht, es gibt berechtigte Gründe zu haben, dies und meiner Meinung nach wäre es eine kleine änderung. Oder bin ich nur nicht springen die rechten Reifen hier?
- Jack & Rory: Die bounty-Periode geht zu Ende, während diese Frage bleibt weitgehend ungelöst, so dass ich nicht daneben, wie diese Frage beantwortet. Noch haben Sie dazu beigetragen, gut und beide teilweise geholfen, so habe ich gestimmt, bis jeder Ihrer Antworten einen slot. Wenn ich die Regeln verstehen, richtig dies bedeutet, Sie teilen die bounty-Punkte.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Mit VS 2010 bin ich nicht zu sehen, das gleiche Verhalten, wie Sie sind. Wenn ich kopiert Ihr die 2 Klassen in einem test-Projekt, und kompiliert bekam ich die Ausgabe:
Also ich kenn EqualsFixutureBase:
Jetzt ist es kompiliert ohne Warnung und wenn ich wählen Sie tests ausführen, die für ExampleOfAnEqualsTestFixture es läuft Foo und alle 5 die geerbte equals-tests. Auch wenn ich kopieren Sie die ExampleOfAnEqualsTestFixture und verwenden Sie es für int und führen Sie die tests für die Lösung, die ich sehe alle 5 geerbt tests laufen (und Weitergabe) für das Beispiel der string-Klasse und der Beispiel-int-Klasse.
Machst du etwas zusätzlich zu Ihrem Beispiel, das könnte die Ursache Ihres Problems?
Den TestClassAttribute können Sie legen Sie die Methoden in der abstrakten Basis. Die IgnoreAttribute schließt die Basisklasse aus der Liste der tests. Ohne die IgnoreAttribute - Attribut-Methoden in Basis ausgeführt werden, für die Basis-Klasse und in Unterklassen gekennzeichnet mit dem TestClassAttribute, .
Out of the box, es sieht aus wie unit-test-Vererbung funktioniert nur, wenn der Basis-test-Klasse in der gleichen assembly wie die abgeleiteten Klassen. Für mich, dies in der Regel Niederlagen der Zweck des habens der Basisklasse. Ich, auch, Wundern, warum es nicht mehr geschrieben über das, auf blogs, und wenn ich könnte etwas fehlen.
Könnten Sie in der Lage sein, um das problem zu umgehen durch die Verknüpfung der Basis-Klasse in jedes Projekt, wo Sie es verwenden möchten. Vielleicht markieren Sie es als intern, so dass die Kopien nicht gegenseitig stören.
Gibt es auch die
TestClassExtensionAttribute
dass Sie erweitern können, um Haken in die test-execution-engine. Ich habe versucht, über Sie zu reflektieren, über die test-Klassen und laden Sie die Basis-Klasse-tests, aber viele der Klassen sind ohne Papiere, und ich konnte es nicht zu funktionieren.Funktioniert es, wenn du die Basis-Klasse " assembly im gleichen Ordner wie die abgeleiteten ein?
Vielleicht ist das, warum, Sie in der gleichen Versammlung arbeitet; die andere Montage ist nicht auflösbar ist an der Stelle Sie es wollen. Ich bin mir nicht sicher, wie Sie Sie sonst um die richtige Sonde Pfade, die Sie brauchen könnten, auf die Zeit, die Sie benötigt. Die .testsettings Ausdrücken können, Dinge wie ein appbase und Sonden für den runner appdomain, vielleicht sind diese korrekt eingerichtet wird helfen, Sie binden an der Basis-Klasse Montage wenn diese anders ist als die Wurzel abgeleitet unit-test-Baugruppe.