Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Shimtypen sind eine von zwei Technologien, die die Microsoft Fakes-Frameworkverwendung, Sie Komponenten in Versuch der Umgebung suchen leicht zu lassen.Shims werden Aufrufe von bestimmten Methoden um, um zu codieren, die Sie als Teil des Tests schreiben.Viele Methoden geben die verschiedenen Ergebnisse zurück, die von externen Bedingungen abhängig sind, aber ein Shim ist der Kontrolle des Tests und kann konsistente Ergebnisse bei jedem Aufruf zurückgeben.Damit werden die Tests viel einfacher zu schreiben.
Verwenden Sie Shims, um den Code von den Assemblys zu suchen, die nicht Teil der Projektmappe sind.Um Komponenten der Projektmappe voneinander isolieren wird empfohlen, Stubs.
Für einen Übersichts- und Schnellstartprozessleitfaden finden Sie unter Isolieren von getestetem Code mithilfe von Microsoft Fakes
Anforderungen
- Visual Studio Ultimate
Siehe Video (1h16): Testen des nicht testfähigen Codes mit Fakes in Visual Studio 2012
In diesem Thema
Hier ist, was Sie in diesem Thema:
Fügen Sie Fakes-Assemblys hinzu
Verwenden Sie ShimsContext
Schreiben Sie Tests mit Shims
Shims für verschiedene Arten von Methoden
Erkennen von Umgebungszugriffen
Aufrufen der ursprünglichen - Methode von der Shimmethode
Beispiel: Der Y2K-Fehler
Fügen Sie eine Methode beachten, die eine Ausnahme am 1. Januar von 2000 ausgelöst wird:
// code under test
public static class Y2KChecker {
public static void Check() {
if (DateTime.Now == new DateTime(2000, 1, 1))
throw new ApplicationException("y2kbug!");
}
}
Diese Methode ist zu testen, da das Programm von DateTime.Now abhängt, eine Methode, die mit der Uhr des Computers abhängig ist, eine umgebungsabhängige, nicht deterministische besonders problematisch.Darüber hinaus ist DateTime.Now eine statische Eigenschaft, deshalb kann ein Stubtyp hier nicht verwendet werden.Dieses Problem ist vom Isolationsproblem im Komponententest sein: Programme, die direkt in Datenbank APIs aufrufen, sind Webdienste, sind usw. schwer in den Komponententest, da ihre Logik der Umgebung abhängt.
Dies ist, wobei Shimtypen verwendet werden sollen.Shimtypen stellen einen Mechanismus, um jede .NET-Methode zu einem benutzerdefinierten Delegaten umzuleiten.Shimtypen werden durch den Fakes-Generator Code-generiert, und sie verwenden Delegaten, die Sie Shimtypen aufrufen, um die neuen Methodenimplementierungen anzugeben.
Die folgenden Testshows, wie der Shimtyp, ShimDateTime verwendet, um eine benutzerdefinierte Implementierung von DateTime.Now bereitzustellen:
//unit test code
// create a ShimsContext cleans up shims
using (ShimsContext.Create()
// hook delegate to the shim method to redirect DateTime.Now
// to return January 1st of 2000
ShimDateTime.NowGet = () => new DateTime(2000, 1, 1);
Y2KChecker.Check();
}
Wie Shims verwendet
Fügen Sie Fakes-Assemblys hinzu
In Erweitern Sie im Projektmappen-Explorer, Verweise des Datenbankkomponententest-Projekts.
- Wenn Sie in Visual Basic arbeiten, müssen Sie Alle Dateien anzeigen in der Symbolleiste des Projektmappen-Explorers auswählen, um die Verweisliste anzuzeigen.
Wählen Sie die Assembly aus, die die Klassendefinitionen enthält, für die Sie Shims erstellen möchten.Wenn Sie DateTime ausgleichen möchten, wählen Sie System.dll
Klicken Sie im Kontextmenü wählen Sie Fakes-Assembly hinzufügen aus.
Verwenden Sie ShimsContext
Wenn, Shim verwenden, Typen eines Komponententestframeworks, müssen Sie den Testcode in ShimsContext einbinden, um die Lebensdauer der Shims zu steuern ein.Wenn Sie nicht mehr benötigen, können Sie die Shims dauern, bis AppDomain heruntergefahren wird.Die einfachste Methode, ShimsContext zu erstellen ist, indem die statische - Methode Create() wie im folgenden Code gezeigt wird:
//unit test code
[Test]
public void Y2kCheckerTest() {
using(ShimsContext.Create()) {
...
} // clear all shims
}
Es ist wichtig, jeden Shimkontext ordnungsgemäß freizugeben.Als Faustregel rufen Sie immer ShimsContext.Create innerhalb einer using-Anweisung auf, um richtiges Löschen der registrierten Shims sicherzustellen.Beispielsweise können Sie einen registrierten Shim für eine Testmethode, die die DateTime.Now-Methode durch einen Delegaten ersetzt, der immer das erste vom Januar 2000 zurückgibt.Wenn Sie vergessen, den registrierten Shim in der Testmethode zu löschen, wird der Rest des Testlaufs immer der erste vom Januar 2000 seit dem DateTime.Now-Wert zurückgeben.Dies könnte überraschend und verwirrend.
Schreiben Sie einen Test mit Shims
In dem Testcode fügen Sie einen Umweg für die Methode, die Sie fälschen möchten.Beispiel:
[TestClass]
public class TestClass1
{
[TestMethod]
public void TestCurrentYear()
{
int fixedYear = 2000;
using (ShimsContext.Create())
{
// Arrange:
// Detour DateTime.Now to return a fixed date:
System.Fakes.ShimDateTime.NowGet =
() =>
{ return new DateTime(fixedYear, 1, 1); };
// Instantiate the component under test:
var componentUnderTest = new MyComponent();
// Act:
int year = componentUnderTest.GetTheCurrentYear();
// Assert:
// This will always be true if the component is working:
Assert.AreEqual(fixedYear, year);
}
}
}
<TestClass()> _
Public Class TestClass1
<TestMethod()> _
Public Sub TestCurrentYear()
Using s = Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create()
Dim fixedYear As Integer = 2000
' Arrange:
' Detour DateTime.Now to return a fixed date:
System.Fakes.ShimDateTime.NowGet = _
Function() As DateTime
Return New DateTime(fixedYear, 1, 1)
End Function
' Instantiate the component under test:
Dim componentUnderTest = New MyComponent()
' Act:
Dim year As Integer = componentUnderTest.GetTheCurrentYear
' Assert:
' This will always be true if the component is working:
Assert.AreEqual(fixedYear, year)
End Using
End Sub
End Class
Shimklassennamen werden gebildet, indem Fakes.Shim zum ursprünglichen Typnamen vorangestellt wird.
Shims funktionieren, mit Umleitungen in den Code der getesteten Anwendung einfügen.Unabhängig wo ein Aufruf der ursprünglichen Methode auftritt, führt das Fakes-System einen Umweg aus, sodass, anstatt die echte Methode aufzurufen, der Shimcode aufgerufen wird.
Beachten Sie, dass Umleitungen zur Laufzeit erstellt und gelöscht werden.Sie müssen einen Umweg innerhalb der Lebensdauer von ShimsContext immer erstellen.Wenn sie freigegeben wird, alle Shims, die Sie erstellt haben, während sie wird entfernt aktiv war.Die beste Möglichkeit, hierzu ist innerhalb einer using-Anweisung.
Sie könnten ein Buildfehler ausgegeben wird, dass der Fakes-Namespace nicht vorhanden ist.Dieser Fehler wird manchmal, wenn es andere Kompilierungsfehler gibt.Beheben Sie die anderen Fehler und er wird.
Shims für verschiedene Arten von Methoden
Shimtypen ermöglichen es Ihnen, jede .NET-Methode, einschließlich statische Methoden oder nicht virtuelle Methoden, durch eigene Delegaten zu ersetzen.
Statische Methoden
Die Eigenschaften, die von Shims auf statische Methoden anzufügen werden in einen Shimtyp eingefügt.Jede Eigenschaft verfügt nur über einen Setter, der verwendet werden kann, um einen Delegaten für die Zielmethode anzufügen.Beispielsweise einer Klasse MyClass mit einer statischen Methode MyMethod angegeben:
//code under test
public static class MyClass {
public static int MyMethod() {
...
}
}
Es können einen Shim zu MyMethod anfügen, der immer 5 zurückgibt:
// unit test code
ShimMyClass.MyMethod = () =>5;
Instanzmethoden (für alle Instanzen)
Entsprechend auf statische Methoden, können Instanzmethoden für alle Instanzen ausgeglichen werden.Die Eigenschaften, um die Shims anzufügen werden in einen geschachtelten Typ gespeichert, der AllInstances, um Verwechslungen auszuschließen genannt wird.Beispielsweise einer Klasse MyClass mit einer Instanzmethode MyMethod angegeben:
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Sie können einen Shim zu MyMethod, der 5 immer zurückgibt, unabhängig von der Instanz anfügen:
// unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;
Die generierte Typstruktur von ShimMyClass-Aussehung wie dem folgenden Code:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public static class AllInstances {
public static Func<MyClass, int>MyMethod {
set {
...
}
}
}
}
Beachten Sie, dass Fakes die Laufzeitinstanz als erstes Argument des Delegaten in diesem Fall übergibt.
Instanzmethoden (für eine Laufzeitinstanz)
Instanzmethoden können aus verschiedenen Delegaten, abhängig vom Empfänger des Aufrufs auch ausgeglichen werden.Dadurch können die gleiche Instanzmethode, um ein anderes Verhalten pro Instanz des Typs enthalten.Die Eigenschaften, um die Shims zu installieren sind Instanzmethoden des Shimtyps selbst.Jeder instanziierte Shimtyp wird auch mit einer ausgeglichenen unformatierten Instanz eines Typs zugeordnet.
Beispielsweise einer Klasse MyClass mit einer Instanzmethode MyMethod angegeben:
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Es können zwei Shimtypen MyMethod installieren, sodass das erste immer 5 zurückgibt und das zweite immer 10 zurückgibt:
// unit test code
var myClass1 = new ShimMyClass()
{
MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };
Die generierte Typstruktur von ShimMyClass-Aussehung wie dem folgenden Code:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public Func<int> MyMethod {
set {
...
}
}
public MyClass Instance {
get {
...
}
}
}
Auf die tatsächliche ausgeglichene Typinstanz kann durch die Instanzeigenschaft zugegriffen werden:
// unit test code
var shim = new ShimMyClass();
var instance = shim.Instance;
Der Shimtyp verfügt auch über eine implizite Konvertierung in ausgeglichenen Typ, sodass Sie den Shimtyp normalerweise einfach verwenden, wie ist:
// unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // implicit cast retrieves the runtime
// instance
Konstruktoren
Konstruktoren können auch ausgeglichen werden, um Shimtypen auf zukünftige Objekten anzufügen.Jeder Konstruktor wird wie ein Konstruktor der statischen - Methode im Shimtyp verfügbar gemacht.Beispielsweise einer Klasse MyClass mit einem Konstruktor zugewiesen, der eine ganze Zahl akzeptiert:
// code under test
public class MyClass {
public MyClass(int value) {
this.Value = value;
}
...
}
Sie installieren den Shimtyp des Konstruktors, sodass jede zukünftige Instanz -5, wenn der Wertsgetter aufgerufen wird, unabhängig vom Wert im Konstruktor zurückgibt:
// unit test code
ShimMyClass.ConstructorInt32 = (@this, value) => {
var shim = new ShimMyClass(@this) {
ValueGet = () => -5
};
};
Beachten Sie, dass jeder Shimtyp zwei Konstruktoren verfügbar macht.Der Standardkonstruktor sollte verwendet werden, wenn eine neue Instanz benötigt wird, während der - Konstruktor, der eine ausgeglichene Instanz als Argument akzeptiert, in den Konstruktorshims nur verwendet werden soll:
// unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }
Die generierte Typstruktur von ShimMyClass ähnelt dem followoing Code:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass>
{
public static Action<MyClass, int> ConstructorInt32 {
set {
...
}
}
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }
...
}
Niedrige Member
Auf die Shimsigenschaften von Basismember können zugegriffen werden, indem ein Shim für den Basistyp erstellt und die untergeordnete Instanz als Parameter für den Konstruktor der Basisklasse Shimklasse übergibt.
Beispielsweise einer Klasse MyBase mit einer Instanzmethode MyMethod und einen Untertyp MyChild angegeben:
public abstract class MyBase {
public int MyMethod() {
...
}
}
public class MyChild : MyBase {
}
Es können einen Shim von MyBase installieren, indem Sie einen neuen ShimMyBase Shim erstellen:
// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };
Beachten Sie, dass der untergeordnete Shimtyp implizit mit der untergeordneten Instanz konvertiert wird, wenn er als Parameter für den - Shimkonstruktor übergeben wird.
Die generierte Typstruktur von ShimMyChild und von ShimMyBase ähnelt dem folgenden Code:
// Fakes generated code
public class ShimMyChild : ShimBase<MyChild> {
public ShimMyChild() { }
public ShimMyChild(Child child)
: base(child) { }
}
public class ShimMyBase : ShimBase<MyBase> {
public ShimMyBase(Base target) { }
public Func<int> MyMethod
{ set { ... } }
}
Statische Konstruktoren
Shimtypen machen eine statische Methode StaticConstructor verfügbar, um den statischen Konstruktor eines Typs auszugleichen.Da statische Konstruktoren nur einmal ausgeführt werden, müssen Sie sicherstellen, dass der Shim konfiguriert wird, bevor auf jeden Member des Typs zugegriffen wird.
Finalizer
Finalizer werden in Fakes nicht unterstützt.
Private-Methoden
Der Fakes-Code-Generator erstellt Shimsigenschaften für private Methoden, die nur sichtbares Typen in der Signatur, IE-Parametertypen .. und Rückgabetyp verfügen, die sichtbar sind.
Binden von Schnittstellen
Wenn ein ausgeglichener Typ eine Schnittstelle implementiert, gibt der Code-Generator eine Methode, die es ermöglicht, alle Member dieser Schnittstelle sofort zu binden.
Beispielsweise einer Klasse MyClass angegeben, die IEnumerable<int> implementiert:
public class MyClass : IEnumerable<int> {
public IEnumerator<int> GetEnumerator() {
...
}
...
}
Es können die Implementierungen von IEnumerable<int> in MyClass ausgleichen, indem Sie die Bindungsmethode aufrufen:
// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });
Die generierte Typstruktur von ShimMyClass ähnelt dem folgenden Code:
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public ShimMyClass Bind(IEnumerable<int> target) {
...
}
}
Ändern des Standardverhaltens
Jeder generierte Shimtyp enthält eine Instanz der IShimBehavior-Schnittstelle, durch die ShimBase<T>.InstanceBehavior-Eigenschaft an.Das Verhalten wird verwendet, wenn ein Client einen Instanzmember aufgerufen wird, der nicht explizit verteilt wurde.
Wenn das Verhalten nicht explizit festgelegt wurde, wird die Instanz, die von der statischen ShimsBehaviors.Current-Eigenschaft zurückgegeben wird.Standardmäßig gibt diese Eigenschaft ein Verhalten zurück, das eine NotImplementedException Ausnahme auslöst.
Dieses Verhalten kann jederzeit geändert werden, indem die - Eigenschaft InstanceBehavior auf jeder Shiminstanz festgelegt wird.Beispielsweise wird der folgende Ausschnitt den Shim zu einem Verhalten, das keine Aktion ausführt oder den Standardwert der Rückgabe, Typ-dass ist, Standard zurückgibt (T):
// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;
Das Verhalten kann für alle Instanzen ausgeglichenen auch global geändert werden, für die die InstanceBehavior-Eigenschaft nicht explizit festgelegt wurde, indem die statische ShimsBehaviors.Current-Eigenschaft festgelegt:
// unit test code
// change default shim for all shim instances
// where the behavior has not been set
ShimsBehaviors.Current =
ShimsBehaviors.DefaultValue;
Erkennen von Umgebungszugriffen
Es ist möglich, ein Verhalten auf alle Member, einschließlich statische Methoden, eines bestimmten Typs anzufügen, indem das ShimsBehaviors.NotImplemented Verhalten der statischen - Eigenschaft Behavior des entsprechenden Shimtyps zugewiesen wird:
// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();
Parallelität
Shimtypen gelten für alle Threads AppDomain zu und weisen keine Threadaffinität auf.Dies ist ein wichtiger Tatsache, wenn Sie vorhaben, einen Test Runner zu verwenden, das Parallelität unterstützen: die Tests, die Shimtypen einbeziehen, können nicht gleichzeitig ausgeführt werden.Diese Eigenschaft wird nicht durch die Fakes-Laufzeit erzwungen.
Aufrufen der ursprünglichen - Methode von der Shimmethode
Stellen Sie sich vor, dass wir den Text am Dateisystem tatsächlich schreiben möchten, nachdem Sie den Dateinamen überprüft haben, der an die Methode übergeben wird.In diesem Fall würden wir die ursprüngliche Methode in der Mitte der Shimmethode aufgerufen werden.
Der erste Ansatz, um dieses Problem zu lösen ist, einen Aufruf an die ursprüngliche Methode mithilfe eines Delegaten und ShimsContext.ExecuteWithoutShims() wie im folgenden Code zu umschließen:
// unit test code
ShimFile.WriteAllTextStringString = (fileName, content) => {
ShimsContext.ExecuteWithoutShims(() => {
Console.WriteLine("enter");
File.WriteAllText(fileName, content);
Console.WriteLine("leave");
});
};
Ein weiterer Ansatz ist, den Shim festzulegen, um ungültig zu machen, die ursprüngliche Methode aufzurufen und den Shim wiederherzustellen.
// unit test code
ShimsDelegates.Action<string, string> shim = null;
shim = (fileName, content) => {
try {
Console.WriteLine("enter”);
// remove shim in order to call original method
ShimFile.WriteAllTextStringString = null;
File.WriteAllText(fileName, content);
}
finally
{
// restore shim
ShimFile.WriteAllTextStringString = shim;
Console.WriteLine("leave");
}
};
// initialize the shim
ShimFile.WriteAllTextStringString = shim;
Einschränkungen
Shims können nicht für alle Typen von der .NET-Basisklassenbibliothek mscorlib und System verwendet werden.
Externe Ressourcen
Empfehlungen
Siehe auch
Konzepte
Isolieren von getestetem Code mithilfe von Microsoft Fakes
Weitere Ressourcen
Der Blog Peter-Hochschulleiters: Visual Studio 2012-Shims
Video (1h16): Testen des nicht testfähigen Codes mit Fakes in Visual Studio 2012