Vzájemná izolace částí aplikace pomocí zástupných procedury za účelem testování částí
Se zakázaným inzerováním jsou jedním ze dvou technologií, které poskytuje umožňují snadno izolovat součást testujete z jiných komponent, které volá rozhraní Microsoft Fakes.Se zakázaným inzerováním je malá část kódu, který probíhá jiná součást během testování.Výhodou použití se zakázaným inzerováním je vrátí konzistentních výsledků snadnější psát test.A to i v případě, že ostatní součásti nejsou ještě práce je možné spustit testy.
Přehled a rychlé spuštění Průvodce předstírá, naleznete v Izolace testovaného kódu pomocí zástupného rozhraní Microsoft.
Chcete-li použít kódy, musíte napsat komponenty tak, aby používala pouze rozhraní, nikoli třídy, chcete-li odkazovat na jiné části aplikace.Totiž dobrý návrh praxe umožňuje změny v jedné části, které jsou méně pravděpodobné, že vyžadují změny v jiném.Pro testování, umožňuje nahradit se zakázaným inzerováním pro skutečné komponenty.
V diagramu komponenty StockAnalyzer je ten, který chceme otestovat.Obvykle používá jiné komponenty, RealStockFeed.Ale RealStockFeed vrací jiné výsledky při každém jeho metody jsou volány, ztěžuje test StockAnalyzer.Během testování, můžeme jej nahradit jinou třídu StubStockFeed.
Protože kódy spoléhají na své schopnosti konstrukce kódu tímto způsobem, obvykle používají kódy izolovat jednu část z jiné aplikace.Chcete-li izolovat od ostatních sestavení, které není pod vaší kontrolou, jako je například System.dll, běžně používáte Překryvné ovladače.Viz téma Izolace aplikace od ostatních sestavení pomocí překrytí za účelem testování částí.
Požadavky
- Visual Studio Ultimate
V tomto tématu
Jak používat kódy
Návrh pro nástřik závislost
Generovat kódy
Napsat Test s kódy
Ověření hodnot parametrů
Jak používat kódy
Návrh pro nástřik závislost
Použijte kódy, aplikace musí být navrženy tak, aby různé součásti nejsou navzájem závislé, nýbrž pouze na definice rozhraní.Namísto probíhá společně v době kompilace, součásti připojeni v době běhu.Tento vzor pomáhá vytvořit software, který je spolehlivý a snadno aktualizovat, protože změny mají tendenci nechcete rozšířit hranice komponenty.Doporučujeme, abyste po jej i v případě, že nebudete používat kódy.Pokud vytváříte nový kód, je snadné sledovat vstřikování závislost vzorek.Pokud vytváříte testy pro stávající software, pravděpodobně budete muset Refaktorovat ji.V případě, že by nepraktické, zvažte místo toho použít Překryvné ovladače.
Začněme motivačních příklad v diagramu této diskuse.Třídy, který čte StockAnalyzer sdílet ceny a generuje některé zajímavé výsledky.Má některé veřejné metody, které chceme otestovat.Aby byly věci co nejjednodušší, stačí Podívejme se na jednu z těchto metod, velmi jednoduchý ten, který hlásí aktuální cena určitého podílu.Chceme psát test jednotky této metody.Zde je první návrh testu:
[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
Jeden problém s Tento test je okamžitě zřejmé: podíl ceny se liší, a tak kontrolní výraz selže.
Další problém může být, aby StockFeed součást, která je používána StockAnalyzer, je stále ve vývoji.Zde je první koncept kód metody podle testu:
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
Takto formulovaná, tato metoda nemusí kompilovat nebo může vyvolat výjimku, protože práce ve třídě StockFeed ještě není dokončena.
Rozhraní vstřikování řeší oba tyto problémy.
Rozhraní vstřikování platí následující pravidla:
Kód komponentů, které aplikace by nikdy explicitně odkazovat na třídy v jiné součásti, prohlášení nebo v new prohlášení.Místo toho použít deklaraci proměnné a parametry rozhraní.Instance komponenty měly by být vytvořeny pouze komponenty kontejneru.
"Součástí" v tomto případě jsme střední třídy nebo skupiny tříd, které můžete vytvářet a aktualizovat společně.Součást je obvykle kódu v jednom projektu sady Visual Studio.Je méně důležité oddělit třídy v rámci jedné součásti, protože jsou aktualizovány ve stejnou dobu.
Také není tak důležitá, chcete-li oddělit součásti od třídy relativně stabilní platformy, jako jsou například System.dll.Psaní rozhraní pro tyto třídy by zbytečně zatěžovat váš kód.
StockAnalyzer kód lze proto vylepšit oddělení z StockFeed pomocí rozhraní následujícím způsobem:
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
V tomto příkladu je předán StockAnalyzer implementace IStockFeed, pokud je vytvořena.Do dokončené aplikace by provést kód inicializace připojení:
analyzer = new StockAnalyzer(new StockFeed())
Pružnější způsoby provádění tohoto připojení.StockAnalyzer může například přijmout tovární objekt, který můžete vytvořit instanci různými implementacemi IStockFeed v různých podmínkách.
Generovat kódy
Jste decoupled třídy, kterou chcete testovat z jiných komponent, které používá.Stejně jako podání více robustní a flexibilní, oddělení umožňuje připojit součásti zkoušeného zóny se zakázaným inzerováním implementace rozhraní pro testovací účely.
Můžete jednoduše napsat prázdný kód jako třídy obvyklým způsobem.Ale Fakes Microsoft vám nabízí dynamičtější způsob, jak vytvořit nejvhodnější se zakázaným inzerováním pro každý test.
Chcete-li použít kódy, musíte nejdříve vygenerovat typy se zakázaným inzerováním z definice rozhraní.
Přidání sestavení předstírá
V Průzkumníku řešení rozbalte projektu Jednotka test odkazy.
- Pokud pracujete v jazyce Visual Basic, musíte vybrat Zobrazit všechny soubory v panelu nástrojů Průzkumníka řešení, chcete-li zobrazit seznam odkazů.
Výběr sestavení, které obsahuje definice rozhraní, pro které chcete vytvořit prázdný kód.
V místní nabídce zvolte Přidat sestavení Fakes.
Napsat test s kódy
[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
Zvláštní část zde kouzelná je třída StubIStockFeed.Microsoft Fakes mechanismus pro všechny veřejné typy v odkazovaných sestavení generuje třídy se zakázaným inzerováním.Název třídy se zakázaným inzerováním je odvozená od názvu rozhraní, s "Fakes.Stub" jako předponu a názvy parametrů typu připojeny.
Kódy jsou také generovány pro mechanismy získání a nastavení vlastností, událostí a obecné metody.
Ověření hodnot parametrů
Můžete ověřit, že pokud vaše komponenta zavolá jiné komponenty, předává správné hodnoty.Kontrolní výrazy můžete umístit buď v testovací kód nebo můžete ukládat hodnoty a ověřte v hlavní části zkoušky.Příklad:
[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
Kódy pro různé druhy členy typu
Metody
Podle popisu v příkladu, můžete být metody prázdná pomocí připojení delegáta k instanci třídy se zakázaným inzerováním.Název typu se zakázaným inzerováním je odvozen z názvu metody a parametry.Mějme například následující rozhraní IMyInterface a metodu MyMethod:
// application under test
interface IMyInterface
{
int MyMethod(string value);
}
Doporučujeme připojit zástupnou proceduru MyMethod, která vždy vrátí 1:
// unit test code
var stub = new StubIMyInterface ();
stub.MyMethodString = (value) => 1;
Pokud se zakázaným inzerováním neposkytují funkce, předstírá vygeneruje funkci, která vrací výchozí hodnotu návratovým typem.Pro čísla, výchozí hodnota je 0 a pro typy tříd je null (C#) nebo Nothing (Visual Basic).
Vlastnosti
Funkce pro nastavení a získání vlastnosti jsou vystaveny jako samostatní delegáti a mohou být samostatně zastoupeny.Zvažte například vlastnost ValueIMyInterface:
// code under test
interface IMyInterface
{
int Value { get; set; }
}
Pro simulaci automatické vlastnosti doporučujeme připojit delegáty k funkci pro nastavení a získání Value:
// unit test code
int i = 5;
var stub = new StubIMyInterface();
stub.ValueGet = () => i;
stub.ValueSet = (value) => i = value;
Pokud nezadáte setter metody nebo typu Get vlastnosti metod se zakázaným inzerováním, vygeneruje předstírá se zakázaným inzerováním, který uchovává hodnoty, tak, aby se zakázaným inzerováním vlastnost funguje jako jednoduché proměnné.
Události
Události jsou vystaveny jako pole delegáta.Výsledkem je, že jakoukoli zastoupenou událost lze jednoduše aktivovat vyvoláním pole zálohování události.Zvažte následující rozhraní pro zastoupení:
// code under test
interface IWithEvents
{
event EventHandler Changed;
}
Pro aktivaci události Changed lze jednoduše vyvolat delegáta zálohování:
// unit test code
var withEvents = new StubIWithEvents();
// raising Changed
withEvents.ChangedEvent(withEvents, EventArgs.Empty);
Obecné metody
Poskytnutím delegáta pro každé zastoupení instance metody je možné vytvořit obecné zástupné metody.Mějme například následující rozhraní obsahující obecnou metodu:
// code under test
interface IGenericMethod
{
T GetValue<T>();
}
můžete napsat test, který stubs GetValue<int> instance:
// unit test code
[TestMethod]
public void TestGetValue()
{
var stub = new StubIGenericMethod();
stub.GetValueOf1<int>(() => 5);
IGenericMethod target = stub;
Assert.AreEqual(5, target.GetValue<int>());
}
Pokud kód k volání GetValue<T> s další instance by zakázaným inzerováním jednoduše zavolejte chování.
Kódy virtuální třídy
V předchozích příkladech byly generovány kódy z rozhraní.Můžete také generovat kódy z třídy, která má virtuální nebo abstraktní členy.Příklad:
// 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; }
}
V testovací kód generovaný z této třídy můžete nastavit delegáta metody pro DoAbstract() a DoVirtual(), ale nikoli DoConcrete().
// unit test
var stub = new Fakes.MyClass();
stub.DoAbstractString = (x) => { Assert.IsTrue(x>0); };
stub.DoVirtualInt32 = (n) => 10 ;
Pokud nezadáte delegáta pro virtuální metody, předstírá můžete buď zadat výchozí chování nebo ho může volat metodu v základní třídě.Aby základní metodu nazvanou, nastavte CallBase vlastnosti:
// 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));
Ladění zástupného kódu
Typy zástupného kódu jsou navrženy pro poskytnutí plynulého zážitku s laděním.Standardně má ladící modul pokyn, aby přešel přes jakýkoli generovaný kód, měl by tedy vstoupit přímo do implementací vlastního člena, které byly připojeny k zástupnému kódu.
Omezení zástupného kódu
Podpisy metody s ukazateli nejsou podporovány.
Uzavřené třídy nebo statické metody nemohou být zastoupeny, protože jsou zastupující typy závislé na odbavení virtuální metody.Pro tyto případy použijte překrývající typy, jak je popsáno v Izolace aplikace od ostatních sestavení pomocí překrytí za účelem testování částí
Změna výchozího chování zástupných kódů
Každý generovaný typ zástupného kódu obsahuje instanci rozhraní IStubBehavior (prostřednictvím vlastnosti IStub.InstanceBehavior).Chování je voláno pokaždé, když klient volá člen bez připojeného vlastního delegáta.Pokud chování nebylo nastaveno, bude používat instanci vrácenou vlastností StubsBehaviors.Current.Standardně vrátí tato vlastnost chování, které vyvolá výjimku NotImplementedException.
Chování lze kdykoliv změnit nastavením vlastnosti InstanceBehavior na jakékoli zástupné instanci.Například následující úryvek změní chování, které nic nedělá nebo vrátí výchozí hodnotu návratového typu: default(T):
// unit test code
var stub = new StubIFileSystem();
// return default(T) or do nothing
stub.InstanceBehavior = StubsBehaviors.DefaultValue;
Chování lze také změnit globálně pro všechny zástupné objekty, pro které nebylo chování nastaveno nastavením vlastnosti StubsBehaviors.Current:
// unit test code
//change default behavior for all stub instances
//where the behavior has not been set
StubBehaviors.Current =
BehavedBehaviors.DefaultValue;
Externí zdroje
Pokyny
Testování pro nepřetržité dodávky s Visual Studio 2012 – kapitola 2: testování: testování vnitřní
Viz také
Koncepty
Izolace testovaného kódu pomocí zástupného rozhraní Microsoft