Sdílet prostřednictvím


Izolace aplikace od ostatních sestavení pomocí překrytí za účelem testování částí

Shim typy jsou jedním ze dvou technologií, které Microsoft Fakes Framework umožňují snadno izoluje komponenty v testu z prostředí.Překryvné ovladače přesměrovat volání specifické metody pro kód, který napíšete jako součást vašeho testu.Mnoho metod vracet odlišné výsledky závislé na vnějším podmínkám, ale doplňkový kód je pod kontrolou vaše zkušební a konzistentní výsledky při každém volání můžete vrátit.Jednodušší testy k zápisu.

Překryvné ovladače slouží k oddělení kódu od sestavení, které nejsou součástí vašeho řešení.Pro izolování součásti řešení od sebe, doporučujeme použít kódy.

Přehled a Stručná pokyny naleznete v tématuIzolace testovaného kódu pomocí zástupného rozhraní Microsoft

Požadavky

  • Visual Studio Ultimate

Viz Video (1 h 16): testování Un-testable kódem předstírá v aplikaci Visual Studio 2012

V tomto tématu

Zde je, co se dozvíte v tomto tématu:

Příklad: Y2K bug

Jak použít Překryvné ovladače

  • Přidání sestavení předstírá

  • Použít ShimsContext

  • Zápis zkoušky s Překryvné ovladače

Překryvné ovladače pro různé druhy metod

Změna výchozího chování

Přistupuje k zjištění prostředí

Souběžnost

Volání metody původní z překrytí metody

Omezení

Příklad: Y2K bug

Zvažte metody, která vyvolá výjimku v 1. leden 2000:

// code under test
public static class Y2KChecker {
    public static void Check() {
        if (DateTime.Now == new DateTime(2000, 1, 1))
            throw new ApplicationException("y2kbug!");
    }
}

Testování tato metoda je zvláště problematické, protože program závisí na DateTime.Now, metoda, která závisí na počítači uživatele hodiny, prostředí závislé, není deterministický metoda.Kromě toho DateTime.Now je statická vlastnost, tak zde nelze použít typ se zakázaným inzerováním.Tento problém je vykazující vydání izolace v testování: programy, které přímo volat do databáze rozhraní API komunikovat s webovými službami a podobně jsou obtížně Jednotkový test, protože jejich logiku závisí na životní prostředí.

Toto je použití typů překrytí.Překrytí typy poskytují mechanismus pro detour jakékoli metody .NET delegát definované uživatelem.Překrytí se kód generovaný generátorem předstírá a delegátů, které nazýváme typy překrytí, používají k určení nové implementace metody.

Následující test ukazuje, jak použít typ překrytí ShimDateTime, chcete-li zadat vlastní implementace DateTime.Now:

//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();
}

Jak použít Překryvné ovladače

Hh549176.collapse_all(cs-cz,VS.110).gifPřidání sestavení předstírá

  1. 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ů.
  2. Výběr sestavení, které obsahuje definice tříd, pro které chcete vytvořit Překryvné ovladače.Chcete-li například pokud chcete shim DateTime, vyberte System.dll

  3. V místní nabídce zvolte Přidat sestavení Fakes.

Hh549176.collapse_all(cs-cz,VS.110).gifPoužít ShimsContext

Používáte-li překrytí typy v rámci zkušební jednotky, musí být testovací kód v ShimsContext k řízení životnosti vaší Překryvné ovladače.Jsme neměl vyžadují-li to, vaše Překryvné ovladače by poslední až do vypnutí domény AppDomain.Nejjednodušší způsob, jak vytvořit ShimsContext je pomocí statické Create() metoda, jak je znázorněno v následujícím kódu:

//unit test code
[Test]
public void Y2kCheckerTest() {
  using(ShimsContext.Create()) {
    ...
  } // clear all shims
}

Je důležité správně nakládat každý kontext překrytí.Jako pravidlem, vždy volat ShimsContext.Create uvnitř using příkaz k zajištění řádné vymazání registrované Překryvné ovladače.Například může zaregistrovat překrytí pro zkušební metoda, která nahrazuje DateTime.Now metodu delegáta, která vždy vrátí první z ledna 2000.Pokud jste zapomněli zrušte registrované překrytí ve zkušební metody, zbytek zkušební jízdy vždy vrátí hodnotu první části dne jako DateTime.Now.Může se jednat o suprising a matoucí.

Hh549176.collapse_all(cs-cz,VS.110).gifNapsat test s Překryvné ovladače

Do kódu test, vložte detour pro metodu, která má být falešné.Příklad:

[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

Názvy tříd překrytí se skládají pomocí prefixu Fakes.Shim k původnímu názvu typu.

Shims práce vložením detours do kódu aplikace zkoušeného.Vždy, když dojde k volání metody původní, provede systém předstírá detour, tak, aby namísto volání skutečné metody, se nazývá kód překrytí.

Všimněte si, že detours se vytvářejí a odstranit v době běhu.Je nutné vytvořit detour během doby existence ShimsContext.Když je uvolněn, jsou odebrány žádné Překryvné ovladače, který jste vytvořili v době, kdy byl aktivní.Nejvhodnějším postupem je uvnitř using prohlášení.

Může se zobrazit sestavení chybová zpráva, že obor názvů předstírá neexistuje.Tato chyba se někdy zobrazí, pokud existují jiné chyby kompilace.Jiné chyby opravit a bude zmizí.

Překryvné ovladače pro různé druhy metod

Překrytí typy umožňují nahradit jakékoli metody rozhraní .NET, včetně statických metod nebo jiných virtuálních metod, s vlastní delegáti.

Hh549176.collapse_all(cs-cz,VS.110).gifStatické metody

Vlastnosti, které chcete připojit Překryvné ovladače na statické metody jsou umístěny v typu překrytí.Každá vlastnost má pouze setter metody, které lze připojit k cílové metodě delegáta.Například mít třídu MyClass pomocí statické metody MyMethod:

//code under test
public static class MyClass {
    public static int MyMethod() {
        ...
    }
}

Doporučujeme připojit překrytí na MyMethod , vždy vrátí 5:

// unit test code
ShimMyClass.MyMethod = () =>5;

Hh549176.collapse_all(cs-cz,VS.110).gifInstance metody (všechny instance)

Podobně pro statické metody lze instanční metody shimmed pro všechny instance.Vlastnosti, které chcete připojit tyto Překryvné ovladače jsou umístěny do vnořeného typu s názvem AllInstances k záměně.Například mít třídu MyClass s metodou instance MyMethod:

// code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

Můžete připojit překrytí na MyMethod , vždy vrátí hodnotu 5, bez ohledu na to, instance:

// unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;

Struktura generovaný typ ShimMyClass vypadá podobně jako následující kód:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public static class AllInstances {
        public static Func<MyClass, int>MyMethod {
            set {
                ...
            }
        }
    }
}

Všimněte si, že Fakes předává instance modulu runtime v tomto případě jako první argument delegáta.

Hh549176.collapse_all(cs-cz,VS.110).gifInstanční metody (pro jednu instanci modulu runtime)

Instanční metody mohou shimmed také různé delegáty, založené na přijímač volání.To umožňuje stejnou metodu instance mají různé chování každou instanci typu.Vlastnosti, které chcete nastavit tyto Překryvné ovladače jsou metody instance typu překrytí, sám.Každý typ instance překrytí souvisí také s raw instance typu shimmed.

Například mít třídu MyClass s metodou instance MyMethod:

// code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

Doporučujeme nastavit dva typy překrytí MyMethod tak, že první z nich vždy vrátí 5 a druhý vždy vrátí 10:

// unit test code
var myClass1 = new ShimMyClass()
{
    MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };

Struktura generovaný typ ShimMyClass vypadá podobně jako následující kód:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public Func<int> MyMethod {
        set {
            ...
        }
    }
    public MyClass Instance {
        get {
            ...
        }
    }
}

Skutečné shimmed typu instance je přístupný prostřednictvím vlastnosti Instance:

// unit test code
var shim = new ShimMyClass();
var instance = shim.Instance;

Typ překrytí má také implicitní převod typu shimmed, je obvykle jednoduše použít překrytí typu, jako je:

// unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // implicit cast retrieves the runtime
                         // instance

Hh549176.collapse_all(cs-cz,VS.110).gifKonstruktory

Konstruktory mohou shimmed také chcete-li připojit typy překrytí na budoucí objekty.Každému konstruktoru je vystavena jako statická metoda konstruktoru typu překrytí.Například mít třídu MyClass s konstruktoru, přičemž celá čísla:

// code under test
public class MyClass {
    public MyClass(int value) {
        this.Value = value;
    }
    ...
}

Nastavení typu překrytí konstruktoru tak, aby každé budoucí instanci vrátí -5, když je vyvolán getter hodnotu, bez ohledu na hodnotu v konstruktoru:

// unit test code
ShimMyClass.ConstructorInt32 = (@this, value) => {
    var shim = new ShimMyClass(@this) {
        ValueGet = () => -5
    };
};

Všimněte si, že každý typ překrytí poskytuje dva konstruktory.Výchozí konstruktor /t čerstvé instance je potřeba při konstruktoru, přičemž shimmed instance, jako argument by měl být používán pouze Překryvné ovladače konstruktoru:

// unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }

Struktura generovaný typ ShimMyClass se podobá followoing kód:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass>
{
    public static Action<MyClass, int> ConstructorInt32 {
        set {
            ...
        }
    }

    public ShimMyClass() { }
    public ShimMyClass(MyClass instance) : base(instance) { }
    ...
}

Hh549176.collapse_all(cs-cz,VS.110).gifZákladní členové

Vytvořením doplňkový kód pro základní typ a předáním instance podřízené jako parametr do konstruktoru třídy základní překrytí je přístupná překrytí vlastnosti základní členy.

Například mít třídu MyBase s metodou instance MyMethod a podtyp MyChild:

public abstract class MyBase {
    public int MyMethod() {
        ...
    }
}

public class MyChild : MyBase {
}

Doporučujeme nastavit překrytí z MyBase vytvořením nového ShimMyBase překrytí:

// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };

Všimněte si, že podřízený typ překrytí je implicitně převeden na podřízené instance, kdy předaný jako parametr do konstruktoru základní překrytí.

Struktura generovaný typ, ShimMyChild a ShimMyBase se podobá následující kód:

// 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 { ... } }
}

Hh549176.collapse_all(cs-cz,VS.110).gifStatické konstruktory

Typy překrytí vystavit statickou metodu StaticConstructor k shim statického konstruktoru typu.Protože statické konstruktory jsou spouštěny po pouze, je třeba zajistit, aby překrytí je nakonfigurován, každý člen typu se před přístupem k.

Hh549176.collapse_all(cs-cz,VS.110).gifFinalizační metody

Předstírá nepodporuje finalizační metody.

Hh549176.collapse_all(cs-cz,VS.110).gifSoukromé metody

Generátor kódu předstírá vytvoří vlastnosti překrytí pro soukromé metody, které mají pouze viditelné typy v podpisu, i.e. typy parametrů a návratový typ viditelné.

Hh549176.collapse_all(cs-cz,VS.110).gifVazba rozhraní

Při shimmed typ implementuje rozhraní, posílá generátor kódu metodu, která umožňuje vytvořit vazbu všech členů z rozhraní najednou.

Například mít třídu MyClass , která implementuje IEnumerable<int>:

public class MyClass : IEnumerable<int> {
    public IEnumerator<int> GetEnumerator() {
        ...
    }
    ...
}

Jsme shim implementace IEnumerable<int> v MyClass voláním metody Bind:

// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });

Struktura generovaný typ ShimMyClass vypadá podobně jako následující kód:

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public ShimMyClass Bind(IEnumerable<int> target) {
        ...
    }
}

Změna výchozího chování

Každý typ generovaného překrytí obsahuje instanci IShimBehavior prostřednictvím rozhraní ShimBase<T>.InstanceBehavior vlastnost.Chování je použita vždy, když klient volá členem instance, která nebyla výslovně shimmed.

Pokud chování nebyla explicitně nastavena, bude používat instanci vrácenou statickou ShimsBehaviors.Current vlastnost.Standardně vrátí tato vlastnost chování, které vyvolá výjimku NotImplementedException.

Toto chování můžete kdykoliv změnit pomocí nastavení InstanceBehavior vlastnost na libovolnou instanci překrytí.Například následující úryvek změní překrytí na chování, které neprovádí žádnou akci nebo vrátí výchozí hodnotu návratový typ – to znamená, že default(T):

// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;

Chování lze také změnit globálně pro všechny instance shimmed u kterého InstanceBehavior nastavením statické nebyla explicitně nastavena vlastnost ShimsBehaviors.Current vlastnosti:

// unit test code
// change default shim for all shim instances
// where the behavior has not been set
ShimsBehaviors.Current = 
    ShimsBehaviors.DefaultValue;

Přistupuje k zjištění prostředí

Je možné připojit ke všem členům, včetně statických metod, přiřazením určitého typu chování ShimsBehaviors.NotImplemented chování do statické vlastnosti Behavior odpovídajícího typu překrytí:

// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();

Souběžnost

Překrytí typy platí pro všechny podprocesy v AppDomain a nemáte k dispozici příbuznosti podprocesu.To je důležité skutečnosti, pokud máte v úmyslu použít testu, které podporují souběžného zpracování: zkoušky týkající se typů překrytí nelze spustit současně.Tato vlastnost není enfored modulem runtime předstírá.

Volání metody původní z překrytí metody

Představte si, že jsme chtěli skutečně zapsat text do systému souborů, po ověření název souboru předaný metodě.V takovém případě by chceme zavolat metodu původní uprostřed metoda překrytí.

První přístup k vyřešení tohoto problému je zabalit volání původní metody pomocí delegáta a ShimsContext.ExecuteWithoutShims() jako v následujícím kódu:

// unit test code
ShimFile.WriteAllTextStringString = (fileName, content) => {
  ShimsContext.ExecuteWithoutShims(() => {

      Console.WriteLine("enter");
      File.WriteAllText(fileName, content);
      Console.WriteLine("leave");
  });
};

Další možností je nastavit překrytí null, zavolejte metodu původní a obnovení překrytí.

// 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;

Omezení

Překryvné ovladače nelze použít u všech typů z knihovny základní třídy rozhraní .NET mscorlib a systému.

Externí zdroje

Hh549176.collapse_all(cs-cz,VS.110).gifPokyny

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

Další zdroje

Peter Provost blogu: Visual Studio 2012 Překryvné ovladače

Video (1 h 16): testování Un-testable kódem předstírá v aplikaci Visual Studio 2012