Isolation du code sous test avec Microsoft FakesIsolating Code Under Test with Microsoft Fakes

Microsoft Fakes vous permet d’isoler le code que vous testez en remplaçant d’autres parties de l’application par des stubs ou des shims.Microsoft Fakes helps you isolate the code you are testing by replacing other parts of the application with stubs or shims. Ce sont de petits segments de code qui sont sous le contrôle de vos tests.These are small pieces of code that are under the control of your tests. En isolant votre code pour les tests, vous savez que si le test échoue, la cause réside dans le code et pas ailleurs.By isolating your code for testing, you know that if the test fails, the cause is there and not somewhere else. Les stubs et les shims vous permettent également de tester votre code même si d'autres parties de votre application ne fonctionnent pas encore.Stubs and shims also let you test your code even if other parts of your application are not working yet.

Microsoft Fakes est disponible en deux versions :Fakes come in two flavors:

  • Un stub remplace une classe par un petit substitut qui implémente la même interface.A stub replaces a class with a small substitute that implements the same interface. Pour utiliser les stubs, vous devez concevoir votre application afin que chaque composant dépende uniquement des interfaces, et non pas d'autres composants.To use stubs, you have to design your application so that each component depends only on interfaces, and not on other components. (Par « composant » nous entendons une classe ou un groupe de classes conçues et mises à jour ensemble et généralement contenues dans un assembly.)(By "component" we mean a class or group of classes that are designed and updated together and typically contained in an assembly.)

  • Un shim modifie le code compilé de votre application au moment de l’exécution pour qu’elle exécute le code shim que votre test fournit au lieu de faire un appel de méthode spécifié.A shim modifies the compiled code of your application at run time so that instead of making a specified method call, it runs the shim code that your test provides. Les shims peuvent être utilisés pour remplacer les appels aux assemblys que vous ne pouvez pas modifier, par exemple les assemblys .NET.Shims can be used to replace calls to assemblies that you cannot modify, such as .NET assemblies.

Fakes remplace les autres composants

SpécificationsRequirements

  • Visual Studio EnterpriseVisual Studio Enterprise
  • Un projet .NET FrameworkA .NET Framework project

Note

Les projets .NET Standard ne sont pas pris en charge..NET Standard projects are not supported.

Choix entre types stub et shimChoosing between stub and shim types

En général, vous considérez un projet Visual Studio comme un composant, car vous développez et mettez à jour ces classes simultanément.Typically, you would consider a Visual Studio project to be a component, because you develop and update those classes at the same time. Vous pouvez envisager d'utiliser des stubs et des shims pour les appels que le projet effectue en direction d'autres projets de votre solution ou d'autres assemblys que le projet référence.You would consider using stubs and shims for calls that the project makes to other projects in your solution, or to other assemblies that the project references.

En règle générale, utilisez des stubs pour les appels dans votre solution Visual Studio et des shims pour les appels vers d'autres assemblys référencés.As a general guide, use stubs for calls within your Visual Studio solution, and shims for calls to other referenced assemblies. En effet, dans votre propre solution, il est conseillé de découpler les composants en définissant les interfaces de la façon requise par l'opération stub.This is because within your own solution it is good practice to decouple the components by defining interfaces in the way that stubbing requires. Cependant, les assemblys externes tels que System.dll ne sont généralement pas fournis avec des définitions d'interface distinctes et vous devez utiliser des shims à la place.But external assemblies such as System.dll typically are not provided with separate interface definitions, so you must use shims instead.

Les autres éléments à prendre en compte sont :Other considerations are:

Performances.Performance. Les shims s'exécutent plus lentement, car ils réécrivent votre code au moment de l'exécution.Shims run slower because they rewrite your code at run time. Les stubs ne subissent pas cette surcharge de performances et sont aussi rapides que les méthodes virtuelles.Stubs do not have this performance overhead and are as fast as virtual methods can go.

Méthodes statiques, types sealed.Static methods, sealed types. Vous pouvez uniquement utiliser les stubs pour implémenter les interfaces.You can only use stubs to implement interfaces. Par conséquent, les types stub ne peuvent pas être utilisés pour les méthodes statiques, les méthodes non virtuelles, les méthodes virtuelles sealed, les méthodes dans les types sealed, etc.Therefore, stub types cannot be used for static methods, non-virtual methods, sealed virtual methods, methods in sealed types, and so on.

Types internes.Internal types. Les stubs et les shims peuvent être utilisés avec les types internes qui sont rendus accessibles à l'aide de l'attribut d'assembly InternalsVisibleToAttribute.Both stubs and shims can be used with internal types that are made accessible by using the assembly attribute InternalsVisibleToAttribute.

Méthodes privées.Private methods. Les shims peuvent remplacer les appels aux méthodes privées si tous les types dans la signature de méthode sont visibles.Shims can replace calls to private methods if all the types on the method signature are visible. Les stubs peuvent uniquement remplacer des méthodes visibles.Stubs can only replace visible methods.

Interfaces et méthodes abstraites.Interfaces and abstract methods. Les stubs fournissent des implémentations d'interfaces et de méthodes abstraites qui peuvent être utilisées lors du test.Stubs provide implementations of interfaces and abstract methods that can be used in testing. Les shims ne peuvent pas instrumenter les interfaces ni les méthodes abstraites, car ils n’ont pas de corps de méthode.Shims can't instrument interfaces and abstract methods, because they don't have method bodies.

En général, nous vous conseillons d'utiliser des types stub pour isoler des dépendances dans votre base de code.In general, we recommend that you use stub types to isolate from dependencies within your codebase. Pour cela, masquez les composants derrière les interfaces.You can do this by hiding the components behind interfaces. Les types shim peuvent être utilisés pour isoler des composants tiers qui ne fournissent pas d'API pouvant être testée.Shim types can be used to isolate from third-party components that do not provide a testable API.

Démarrage avec les stubsGetting started with stubs

Pour obtenir une description détaillée, consultez Utilisation de stubs pour isoler des parties de votre application les unes des autres pour des tests unitaires.For a more detailed description, see Using stubs to isolate parts of your application from each other for unit testing.

  1. Injecter des interfacesInject interfaces

    Pour utiliser les stubs, vous devez écrire le code que vous souhaitez tester de telle sorte qu'il ne mentionne pas explicitement les classes d'un autre composant de votre application.To use stubs, you have to write the code you want to test in such a way that it does not explicitly mention classes in another component of your application. Par « composant » nous entendons une ou plusieurs classes développées et mises à jour ensemble et généralement contenues dans un projet Visual Studio.By "component" we mean a class or classes that are developed and updated together, and typically contained in one Visual Studio project. Les variables et les paramètres doivent être déclarés à l'aide d'interfaces et les instances des autres composants doivent être passées ou créées à l'aide d'une fabrique.Variables and parameters should be declared by using interfaces and instances of other components should be passed in or created by using a factory. Par exemple, si StockFeed est une classe dans un autre composant de l'application, le résultat est incorrect :For example, if StockFeed is a class in another component of the application, then this would be considered bad:

    return (new StockFeed()).GetSharePrice("COOO"); // Bad

    Au lieu de cela, définissez une interface qui peut être implémentée par l'autre composant, et qui peut également être implémentée par un stub à des fins de test :Instead, define an interface that can be implemented by the other component, and which can also be implemented by a stub for test purposes:

    public int GetContosoPrice(IStockFeed feed)
    { return feed.GetSharePrice("COOO"); }
    
    Public Function GetContosoPrice(feed As IStockFeed) As Integer
     Return feed.GetSharePrice("COOO")
    End Function
    
  2. Ajouter un assembly FakesAdd Fakes Assembly

    1. Dans l’Explorateur de solutions, développez la liste de références du projet de test.In Solution Explorer, expand the test project's reference list. Si vous utilisez Visual Basic, vous devez choisir Afficher tous les fichiers pour afficher la liste des références.If you are working in Visual Basic, you must choose Show All Files in order to see the reference list.

    2. Sélectionnez la référence à l'assembly dans lequel l'interface (par exemple IStockFeed) est définie.Select the reference to the assembly in which the interface (for example IStockFeed) is defined. Dans le menu contextuel de cette référence, choisissez Ajouter un assembly Fakes.On the shortcut menu of this reference, choose Add Fakes Assembly.

    3. Régénérez la solution.Rebuild the solution.

  3. Dans vos tests, construisez les instances du stub et fournissez le code pour ses méthodes :In your tests, construct instances of the stub and provide code for its methods:

    [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
    

    Ici, l'aspect le plus magique est la classe StubIStockFeed.The special piece of magic here is the class StubIStockFeed. Pour chaque interface de l'assembly référencé, le mécanisme Microsoft Fakes génère une classe stub.For every interface in the referenced assembly, the Microsoft Fakes mechanism generates a stub class. Le nom de la classe stub est dérivé du nom de l'interface, précédé de "Fakes.Stub", et auquel sont ajoutés les noms de types de paramètre.The name of the stub class is the derived from the name of the interface, with "Fakes.Stub" as a prefix, and the parameter type names appended.

    Les stubs sont également générés pour les accesseurs Get et les méthodes setter de propriétés, les événements et les méthodes génériques.Stubs are also generated for the getters and setters of properties, for events, and for generic methods. Pour plus d’informations, consultez Utilisation de stubs pour isoler des parties de votre application les unes des autres pour des tests unitaires.For more information, see Using stubs to isolate parts of your application from each other for unit testing.

Démarrage avec les shimsGetting started with shims

(Pour obtenir une description détaillée, consultez Utilisation de shims pour isoler votre application des autres assemblys pour des tests unitaires.)(For a more detailed description, see Using shims to isolate your application from other assemblies for unit testing.)

Supposons que votre composant contienne des appels à DateTime.Now :Suppose your component contains calls to DateTime.Now:

// Code under test:
    public int GetTheCurrentYear()
    {
       return DateTime.Now.Year;
    }

Pendant le test, placez un shim sur la propriété Now, car la vraie version retourne incommodément une valeur différente à chaque appel.During testing, you would like to shim the Now property, because the real version inconveniently returns a different value at every call.

Pour utiliser des shims, vous ne devez pas modifier le code de l’application ni l’écrire d’une façon particulière.To use shims, you don't have to modify the application code or write it a particular way.

  1. Ajouter un assembly FakesAdd Fakes Assembly

    Dans l’Explorateur de solutions, ouvrez les références de votre projet de test unitaire et sélectionnez la référence à l’assembly qui contient la méthode que vous souhaitez simuler.In Solution Explorer, open your unit test project's references and select the reference to the assembly that contains the method you want to fake. Dans cet exemple, la classe DateTime se trouve dans System.dll.In this example, the DateTime class is in System.dll. Pour afficher les références dans un projet Visual Basic, choisissez Afficher tous les fichiers.To see the references in a Visual Basic project, choose Show All Files.

    Choisissez Ajouter un assembly Fakes.Choose Add Fakes Assembly.

  2. Insérer un shim dans ShimsContextInsert a shim in a ShimsContext

    [TestClass]
    public class TestClass1
    {
            [TestMethod]
            public void TestCurrentYear()
            {
                int fixedYear = 2000;
    
                // Shims can be used only in a ShimsContext:
                using (ShimsContext.Create())
                {
                  // Arrange:
                    // Shim 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
    

    Les noms de classe de shim sont obtenus en ajoutant le préfixe Fakes.Shim au nom de type d'origine.Shim class names are made up by prefixing Fakes.Shim to the original type name. Les noms de paramètres sont ajoutés au nom de la méthode.Parameter names are appended to the method name. (Vous ne devez ajouter aucune référence d’assembly à System.Fakes)(You don't have to add any assembly reference to System.Fakes.)

L'exemple précédent utilise un shim pour une méthode statique.The previous example uses a shim for a static method. Pour utiliser un shim pour une méthode d'instance, écrivez AllInstances entre le nom du type et le nom de la méthode :To use a shim for an instance method, write AllInstances between the type name and the method name:

System.IO.Fakes.ShimFile.AllInstances.ReadToEnd = ...

(Il n’existe aucun assembly « System.IO.Fakes » à référencer.(There is no 'System.IO.Fakes' assembly to reference. L'espace de noms est généré par le processus de création de shim.The namespace is generated by the shim creation process. Toutefois, vous pouvez utiliser « using » ou « Import » de la façon habituelle.)But you can use 'using' or 'Import' in the usual way.)

Vous pouvez également créer des shims pour des instances spécifiques, des constructeurs et des propriétés.You can also create shims for specific instances, for constructors, and for properties. Pour plus d’informations, consultez Utilisation de shims pour isoler votre application des autres assemblys pour des tests unitaires.For more information, see Using shims to isolate your application from other assemblies for unit testing.

Dans cette sectionIn this section

Utilisation de stubs pour isoler des parties de votre application les unes des autres pour des tests unitairesUsing stubs to isolate parts of your application from each other for unit testing

Utilisation de shims pour isoler votre application des autres assemblys pour des tests unitairesUsing shims to isolate your application from other assemblies for unit testing

Génération, compilation de code et conventions d’affectation de noms dans Microsoft FakesCode generation, compilation, and naming conventions in Microsoft Fakes