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.
Stubtypen sind eine von zwei Technologien, die das Microsoft Fakes-Framework bereitstellt, um Sie eine Komponente suchen leicht zu ermöglichen, die Sie, von anderen Komponenten testen, die sie aufruft.Ein Stub ist ein kleiner des Codes, der einer anderen Komponente während Tests stattfindet.Der Vorteil der Verwendung eines Stubs ist, dass er die konsistente Ergebnisse zurückgibt und den Test einfacher zu schreiben macht.Außerdem können Sie Tests ausführen, auch wenn die anderen Komponenten noch nicht arbeiten.
Eine Übersicht und ein Schnellstart-Handbuch zu Fakes finden Sie unter Isolieren von getestetem Code mithilfe von Microsoft Fakes.
Um Stubs zu verwenden, müssen Sie die Komponente, sodass sie nur Schnittstellen verwendet keine Klassen schreiben, um andere Teile der Anwendung zugreifen.Dies empfiehlt Entwurfsüblich, da Änderungen in ein Teil unwahrscheinlich, Änderungen in anderen benötigen vornimmt.Für das Testen ermöglicht es Ihnen, einen Stub für eine reale Komponente zu ersetzen.
Im Diagramm ist das Teil-StockAnalyzer das, das Sie testen möchten.Es verwendet normalerweise eine andere Komponente, RealStockFeed.Die RealStockFeed gibt die verschiedenen Ergebnisse, wenn seine Methoden aufgerufen werden zurück und macht es schwierig, StockAnalyzer zu testen.Während des Tests ersetzen Sie ihn durch eine andere Klasse, StubStockFeed.
.png)
Da Stubs auf dem in der Lage sein, den Code auf diese Weise zu strukturieren benötigen, verwenden Sie normalerweise Stubs, um einen Teil der Anwendung von anderen zu suchen.Um sie von anderen Assemblys erforderlich die nicht unter dem - Steuerelement, wie System.dll, Sie sind ist normalerweise Shims verwenden.Siehe Verwenden von Shims, um zu Komponententests die Anwendung von anderen Assemblys zu trennen.
Anforderungen
- Visual Studio Ultimate
In diesem Thema
Wie Stubs verwendet
Entwurf für Abhängigkeitseinfügung
Generieren Sie Stubs
Schreiben Sie den Test mit Stubs
Überprüfen von Parameterwerten
Wie Stubs verwendet
Entwurf für Abhängigkeitseinfügung
Um Stubs zu verwenden, muss die Anwendung entworfen werden für die verschiedenen Komponenten nicht voneinander abhängig sind, aber nur abhängig von den Schnittstellendefinitionen.Anstatt, zur Kompilierungszeit verknüpft werden, verbunden werden Komponenten zur Laufzeit.Dieses Muster erleichtert, Software zu machen, die robust und leicht zu aktualisieren ist, da Änderungen, werden nicht über Teilgrenzen weitergegeben.Es empfiehlt sich, diesem zu folgen, auch wenn Sie nicht Stubs.Wenn Sie neuen Code schreiben, ist es einfach, dem Abhängigkeitseinfügung Muster folgen.Wenn Sie Tests für vorhandene Software schreiben, müssen Sie diese ggf. umgestalten.Wenn das unmöglich wäre, können Sie mithilfe der Shims stattdessen berücksichtigen.
Sehen Sie sich diese Diskussion mit einem Motivierungsbeispiel, das beginnen im Diagramm.Die - Klasse StockAnalyzer liest Aktienkurse und generiert mehrere interessante Ergebnisse.Sie verfügt über mehrere öffentliche Methoden, die Sie testen möchten.Um Dinge einfach zu halten, wird hier nur eine dieser Methoden, ein sehr einfaches das Betrachten der aktuellen Preis einer bestimmten Freigabe gemeldet.Sie möchten einen Komponententest dieser Methode schreiben.Hier ist der erste Entwurf eines Tests:
[TestMethod]
public void TestMethod1()
{
// Arrange:
var analyzer = new StockAnalyzer();
// Act:
var result = analyzer.GetContosoPrice();
// Assert:
Assert.AreEqual(123, result); // Why 123?
}
<TestMethod()> Public Sub TestMethod1()
' Arrange:
Dim analyzer = New StockAnalyzer()
' Act:
Dim result = analyzer.GetContosoPrice()
' Assert:
Assert.AreEqual(123, result) ' Why 123?
End Sub
Ein Problem mit diesem Test liegt sofort offensichtlich: Aktienkurse unterscheiden sich deshalb schlägt die Assertion normalerweise aus.
Ein weiteres Problem kann, dass die StockFeed-Komponente, die vom StockAnalyzer verwendet wird, noch in der Entwicklungsphase befindet.Hier ist der erste Entwurf des Codes der zu testende Methode:
public int GetContosoPrice()
{
var stockFeed = new StockFeed(); // NOT RECOMMENDED
return stockFeed.GetSharePrice("COOO");
}
Public Function GetContosoPrice()
Dim stockFeed = New StockFeed() ' NOT RECOMMENDED
Return stockFeed.GetSharePrice("COOO")
End Function
unter den angegebenen Bedingungen hat diese Methode möglicherweise nicht kompilierte oder eine Ausnahme aus, da Arbeit in den StockFeed-Klasse noch nicht abgeschlossen ist.
Schnittstelleneinfügung werden beiden Probleme an.
Schnittstelleneinfügung wendet die folgende Regel an:
Der Code aller Komponenten der Anwendung sollte eine Klasse in einer anderen Komponente, entweder in einer Deklaration oder in einer new-Anweisung niemals explizit verweisen.Stattdessen sollten Variablen und Parameter mit Schnittstellen deklariert werden.Komponenteninstanzen sollten nur von den Container der Komponente erstellt werden.
Durch "Komponente" in diesem Fall bedeuten wir eine Klasse oder eine Gruppe von Klassen, die zusammen entwickeln und aktualisieren.In der Regel ist eine Komponente der Code in einem Visual Studio-Projekt.Es ist weniger wichtig, Klassen in einer Komponente zu entkoppeln, da sie gleichzeitig aktualisiert werden.
Es ist auch nicht so wichtig, die Komponenten von Klassen einer relativ stabilen Plattform wie System.dll zu entkoppeln.Schreibenschnittstellen für alle diese Klassen entsprechen den Code überlasten.
Der StockAnalyzer-Code kann durch das Entkoppeln er vom StockFeed daher verbessert werden, indem eine Schnittstelle so verwendet:
public interface IStockFeed
{
int GetSharePrice(string company);
}
public class StockAnalyzer
{
private IStockFeed stockFeed;
public Analyzer(IStockFeed feed)
{
stockFeed = feed;
}
public int GetContosoPrice()
{
return stockFeed.GetSharePrice("COOO");
}
}
Public Interface IStockFeed
Function GetSharePrice(company As String) As Integer
End Interface
Public Class StockAnalyzer
' StockAnalyzer can be connected to any IStockFeed:
Private stockFeed As IStockFeed
Public Sub New(feed As IStockFeed)
stockFeed = feed
End Sub
Public Function GetContosoPrice()
Return stockFeed.GetSharePrice("COOO")
End Function
End Class
In diesem Beispiel wird StockAnalyzer eine Implementierung von einem IStockFeed übergeben, wenn es erstellt wird.In der abgeschlossenen Anwendung würde der Initialisierungscode die Verbindung ausführen:
analyzer = new StockAnalyzer(new StockFeed())
Es gibt flexiblere Methoden der Ausführung dieser Verbindung.Beispielsweise kann StockAnalyzer ein Factoryobjekt akzeptieren, das verschiedene Implementierungen von IStockFeed in verschiedenen Bedingungen instanziiert werden kann.
Generieren Sie Stubs
Sie haben die Klasse entkoppelt, die Sie von den anderen Komponenten testen möchten, die sie verwendet.Genauso wie das Erstellen des Antrags robuster und flexibler, das Entkoppeln ermöglicht Ihnen, die Komponente getesteten an Stubimplementierungen der Schnittstellen für Testzwecke herzustellen.
Sie können die Stubs als Klassen einfach wie normalerweise schreiben.Die Microsoft Fakes bietet eine dynamischeren Methode, die die meisten erstellen entsprechender Stub für jeden Test.
Um Stubs zu verwenden, müssen Sie Stubtypen von Schnittstellendefinitionen zuerst generieren.
Hinzufügen eines Fakes-Assemblys
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 Schnittstellendefinitionen enthält, für die Sie Stubs erstellen möchten.
Klicken Sie im Kontextmenü wählen Sie Fakes-Assembly hinzufügen aus.
Schreiben Sie den Test mit Stubs
[TestClass]
class TestStockAnalyzer
{
[TestMethod]
public void TestContosoStockPrice()
{
// Arrange:
// Create the fake stockFeed:
IStockFeed stockFeed =
new StockAnalysis.Fakes.StubIStockFeed() // Generated by Fakes.
{
// Define each method:
// Name is original name + parameter types:
GetSharePriceString = (company) => { return 1234; }
};
// In the completed application, stockFeed would be a real one:
var componentUnderTest = new StockAnalyzer(stockFeed);
// Act:
int actualValue = componentUnderTest.GetContosoPrice();
// Assert:
Assert.AreEqual(1234, actualValue);
}
...
}
<TestClass()> _
Class TestStockAnalyzer
<TestMethod()> _
Public Sub TestContosoStockPrice()
' Arrange:
' Create the fake stockFeed:
Dim stockFeed As New StockAnalysis.Fakes.StubIStockFeed
With stockFeed
.GetSharePriceString = Function(company)
Return 1234
End Function
End With
' In the completed application, stockFeed would be a real one:
Dim componentUnderTest As New StockAnalyzer(stockFeed)
' Act:
Dim actualValue As Integer = componentUnderTest.GetContosoPrice
' Assert:
Assert.AreEqual(1234, actualValue)
End Sub
End Class
Das spezielle Elemente für Magie hier ist die - Klasse StubIStockFeed.Für jeden öffentlichen Typ in der Assembly, auf die verwiesen wird, generiert der Microsoft Fakes-Mechanismus eine Stubklasse.Der Name der Stubklasse ist die angefügten abgeleiteten vom Namen der Schnittstelle, mit "Fakes.Stub" als Präfix, und Parametertypnamen.
Stubs werden auch für die get-Accessor und die Setter für von Eigenschaften, Ereignisse und für generische Methoden generiert.
Überprüfen von Parameterwerten
Sie können überprüfen, dass, wenn die Komponente einen Aufruf einer anderen Komponente macht, sie die richtigen Werte übergibt.Sie können entweder eine Assertion im Stub einfügen, oder Sie können den Wert speichern und im Hauptteil des Tests überprüfen.Beispiel:
[TestClass]
class TestMyComponent
{
[TestMethod]
public void TestVariableContosoPrice()
{
// Arrange:
int priceToReturn;
string companyCodeUsed;
var componentUnderTest = new StockAnalyzer(new StubIStockFeed()
{
GetSharePriceString = (company) =>
{
// Store the parameter value:
companyCodeUsed = company;
// Return the value prescribed by this test:
return priceToReturn;
};
};
// Set the value that will be returned by the stub:
priceToReturn = 345;
// Act:
int actualResult = componentUnderTest.GetContosoPrice(priceToReturn);
// Assert:
// Verify the correct result in the usual way:
Assert.AreEqual(priceToReturn, actualResult);
// Verify that the component made the correct call:
Assert.AreEqual("COOO", companyCodeUsed);
}
...}
<TestClass()> _
Class TestMyComponent
<TestMethod()> _
Public Sub TestVariableContosoPrice()
' Arrange:
Dim priceToReturn As Integer
Dim companyCodeUsed As String = ""
Dim stockFeed As New StockAnalysis.Fakes.StubIStockFeed()
With stockFeed
' Implement the interface's method:
.GetSharePriceString = _
Function(company)
' Store the parameter value:
companyCodeUsed = company
' Return a fixed result:
Return priceToReturn
End Function
End With
' Create an object to test:
Dim componentUnderTest As New StockAnalyzer(stockFeed)
' Set the value that will be returned by the stub:
priceToReturn = 345
' Act:
Dim actualResult As Integer = componentUnderTest.GetContosoPrice()
' Assert:
' Verify the correct result in the usual way:
Assert.AreEqual(priceToReturn, actualResult)
' Verify that the component made the correct call:
Assert.AreEqual("COOO", companyCodeUsed)
End Sub
...
End Class
Stubs für verschiedene Arten von Typmembern
Methoden
Wie im Beispiel beschrieben, Methoden gerodet werden, indem Sie einen Delegaten an eine Instanz der Stubklasse angefügt werden.Der Name des Stubtyps wird von den Namen der Methode und der - Parameter abgeleitet.In der folgenden IMyInterface-Schnittstelle und die - Methode MyMethod angegeben:
// application under test
interface IMyInterface
{
int MyMethod(string value);
}
Es fügen einen Stub zu MyMethod an, der immer 1 zurückgibt:
// unit test code
var stub = new StubIMyInterface ();
stub.MyMethodString = (value) => 1;
Wenn Sie einen Stub für eine Funktion nicht bereitstellen, generiert Fakes eine Funktion, die den Standardwert des Rückgabetyps zurückgibt.Für Zahlen ist der Standardwert 0, und für Klassentypen ist es null (C#) oder Nothing (Visual Basic).
Eigenschaften
Eigenschaftgetter und -setzer werden als separate Delegaten verfügbar gemacht und können separat gerodet werden.Betrachten Sie beispielsweise die - Eigenschaft Value von IMyInterface:
// code under test
interface IMyInterface
{
int Value { get; set; }
}
Es fügen Delegaten dem get-Accessor und dem Setter von Value an, um eine AUTOEigenschaft zu simulieren:
// unit test code
int i = 5;
var stub = new StubIMyInterface();
stub.ValueGet = () => i;
stub.ValueSet = (value) => i = value;
Wenn Sie Stubmethoden entweder nicht für den Setter oder den get-Accessor einer Eigenschaft bereitstellen, generiert Fakes einen Stub, der Werte speichert, sodass die Stubeigenschaft als einfache Variable funktioniert.
Ereignisse
Ereignisse werden als Delegatfelder verfügbar gemacht.Daher kann jedes Ereignis mit Stub einfach ausgelöst werden, indem das Ereignisdahinte liegendes Feld aufruft.Sehen Sie sich die folgende Schnittstelle überprüfen, um zu roden:
// code under test
interface IWithEvents
{
event EventHandler Changed;
}
Um das Changed-Ereignis auszulösen, rufen Sie einfach den Schutzträgerdelegaten auf:
// unit test code
var withEvents = new StubIWithEvents();
// raising Changed
withEvents.ChangedEvent(withEvents, EventArgs.Empty);
Generische Methoden
Es ist möglich, generische Methoden zu roden, indem Sie einen Delegaten für jede gewünschte Instanziierung der Methode bereitstellt.In der folgenden Schnittstelle angegeben, die eine generische Methode enthält:
// code under test
interface IGenericMethod
{
T GetValue<T>();
}
Sie können einen Test schreiben, der die GetValue<int>-Instanziierung erstellt einen Stub für:
// unit test code
[TestMethod]
public void TestGetValue()
{
var stub = new StubIGenericMethod();
stub.GetValueOf1<int>(() => 5);
IGenericMethod target = stub;
Assert.AreEqual(5, target.GetValue<int>());
}
Wenn der Code, GetValue<T> bei jeder anderen Instanziierung aufzurufen, müsste der Stub einfach das Verhalten aufrufen.
Stubs von virtuellen Klassen
In den vorherigen Beispielen sind die Stubs von Schnittstellen generiert wurde.Sie können Stubs von einer Klasse auch generieren, die die virtuelle oder abstrakte Member.Beispiel:
// Base class in application under test
public abstract class MyClass
{
public abstract void DoAbstract(string x);
public virtual int DoVirtual(int n)
{ return n + 42; }
public int DoConcrete()
{ return 1; }
}
Im Stub, der von dieser Klasse generiert wird, können Sie für DoAbstract() Delegatenmethoden erstellt und DoVirtual(), jedoch nicht DoConcrete() festlegen.
// unit test
var stub = new Fakes.MyClass();
stub.DoAbstractString = (x) => { Assert.IsTrue(x>0); };
stub.DoVirtualInt32 = (n) => 10 ;
Wenn Sie einen Delegaten nicht für eine virtuelle Methode bereitstellen, kann Fakes entweder das Standardverhalten bereitstellen, oder es kann die Methode in der Basisklasse aufrufen.Um die - Basismethode aufgerufen wird, legen Sie die CallBase-Eigenschaft fest:
// unit test code
var stub = new Fakes.MyClass();
stub.CallBase = false;
// No delegate set – default delegate:
Assert.AreEqual(0, stub.DoVirtual(1));
stub.CallBase = true;
//No delegate set - calls the base:
Assert.AreEqual(43,stub.DoVirtual(1));
Debuggingsstubs
Die Stubtypen wurden entwickelt, um eine glatte Debugleistung bereitzustellen.Standardmäßig wird der Debugger angewiesen, über einen beliebigen generierten Code zu durchlaufen, daher sollte er direkt in die benutzerdefinierten Memberimplementierungen treten, die dem Stub angefügt waren.
Stubeinschränkungen
Methodensignaturen mit Zeigern werden nicht unterstützt.
Versiegelte Klassen oder statische Methoden können nicht gerodet werden, da Stubtypen in virtuellen Methodendispatch basieren.Für solche Fälle Verwendungsshimtypen, wie in beschrieben Verwenden von Shims, um zu Komponententests die Anwendung von anderen Assemblys zu trennen
Ändern des Standardverhaltens der Stubs
Jeder generierte Stubtyp enthält eine Instanz der IStubBehavior-Schnittstelle an (über die - Eigenschaft IStub.InstanceBehavior ).Das Verhalten wird immer dann aufgerufen, wenn ein Client einen Member ohne angefügten benutzerdefinierten Delegaten aufrufen.Wenn das Verhalten nicht festgelegt wurde, wird die Instanz, die von der StubsBehaviors.Current-Eigenschaft zurückgegeben wird.Standardmäßig gibt diese Eigenschaft ein Verhalten zurück, das eine NotImplementedException Ausnahme auslöst.
Das Verhalten kann jederzeit geändert werden, indem die - Eigenschaft InstanceBehavior auf jeder Stubinstanz festgelegt wird.Beispielsweise wird der folgende Ausschnitt ein Verhalten, das keine Aktion ausführt oder den Standardwert des Rückgabetyps zurückgibt: default(T):
// unit test code
var stub = new StubIFileSystem();
// return default(T) or do nothing
stub.InstanceBehavior = StubsBehaviors.DefaultValue;
Das Verhalten kann für alle Stubobjekte auch global geändert werden, für die das Verhalten nicht festgelegt wurde, indem Sie die - Eigenschaft festgelegt hat StubsBehaviors.Current:
// unit test code
//change default behavior for all stub instances
//where the behavior has not been set
StubBehaviors.Current =
BehavedBehaviors.DefaultValue;