Comment tester des méthodes statiques en C #

Lors de la création ou de l'utilisation d'applications .NET, vous pouvez souvent utiliser des méthodes statiques. Les méthodes en C # peuvent être statiques ou non statiques. Une méthode non statique (également appelée méthode d'instance) peut être appelée sur une instance de la classe à laquelle elle appartient. Les méthodes statiques n'ont pas besoin d'une instance de la classe pour être appelées - elles peuvent être appelées sur la classe elle-même.

Bien que tester une méthode non statique (au moins une qui n'appelle pas de méthode statique ou n'interagit pas avec des dépendances externes) soit simple, tester une méthode statique n'est pas du tout une tâche facile. Cet article explique comment surmonter ce défi et tester des méthodes statiques en C #. 

[Aussi sur: Comment refactoriser des objets Dieu en C #]

Pour utiliser les exemples de code fournis dans cet article, vous devez disposer de Visual Studio 2019 installé sur votre système. Si vous n'en avez pas déjà une copie, vous pouvez télécharger Visual Studio 2019 ici.  

Créer un projet d'application console .NET Core dans Visual Studio

Tout d'abord, créons un projet d'application de console .NET Core dans Visual Studio. En supposant que Visual Studio 2019 est installé sur votre système, suivez les étapes décrites ci-dessous pour créer un nouveau projet d'application console .NET Core dans Visual Studio.

  1. Lancez l'IDE de Visual Studio.
  2. Cliquez sur "Créer un nouveau projet".
  3. Dans la fenêtre «Créer un nouveau projet», sélectionnez «Application console (.NET Core)» dans la liste des modèles affichés.
  4. Cliquez sur Suivant.
  5. Dans la fenêtre «Configurer votre nouveau projet» ci-dessous, spécifiez le nom et l'emplacement du nouveau projet.
  6. Cliquez sur Créer. 

Cela créera un nouveau projet d'application console .NET Core dans Visual Studio 2019. De la même manière, créez deux autres projets: une bibliothèque de classes et un projet de test unitaire (test xUnit). Nous utiliserons ces trois projets pour illustrer les tests unitaires de méthodes statiques dans les sections suivantes de cet article.

Quand une méthode statique peut et ne peut pas être testée unitaire

Le test unitaire d'une méthode statique n'est pas différent du test unitaire d'une méthode non statique. Les méthodes statiques ne sont pas incontestables en elles-mêmes. Une méthode statique qui ne contient aucun état ou ne change pas d'état peut être testée unitaire. Tant que la méthode et ses dépendances sont idempotentes, la méthode peut être testée unitaire. Les problèmes surviennent lorsque la méthode statique appelle d'autres méthodes ou lorsque l'objet testé appelle la méthode statique. D'un autre côté, si l'objet testé appelle une méthode d'instance, vous pouvez le tester facilement.

Une méthode statique ne peut pas être testée unitaire si l'une des conditions suivantes est vraie: 

  • La méthode statique interagit avec des dépendances externes telles qu'une base de données, un système de fichiers, un réseau ou une API externe.
  • La méthode statique contient des informations d'état, c'est-à-dire si elle met en cache des données dans un objet statique de la classe.

Considérez l'extrait de code suivant qui montre deux classes, à savoir ProductBL et Logger. Alors que ProductBL est une classe non statique, Logger est une classe statique. Notez que la méthode Write de la classe Logger a été appelée à partir de la méthode LogMessage de la classe ProductBL.

classe publique ProductBL

    {

        public void LogMessage (message sous forme de chaîne)

        {

            Logger.Write (message);

        }

    }

    enregistreur de classe publique

    {

        public static void Write (chaîne de message)

        {

           // Écrivez votre code ici pour enregistrer les données

        }

    }

Supposons que la méthode Write de la classe Logger se connecte à une base de données, puis écrit les données dans une table de base de données. Le nom de la base de données et sa table dans laquelle les données doivent être écrites peuvent être préconfigurés dans le fichier appsettings.json. Comment pouvez-vous maintenant écrire des tests unitaires pour la méthode ProductBL?

Notez que les méthodes statiques ne peuvent pas être simulées facilement. Par exemple, si vous avez deux classes nommées A et B et que la classe A utilise un membre statique de la classe B, vous ne pourrez pas tester la classe A de manière isolée.

Trois méthodes de test unitaire des méthodes statiques

Vous pouvez utiliser Moq pour simuler des méthodes non statiques, mais il ne peut pas être utilisé pour simuler des méthodes statiques. Bien que les méthodes statiques ne puissent pas être facilement simulées, il existe plusieurs façons de se moquer des méthodes statiques.

Vous pouvez tirer parti du framework Moles or Fakes de Microsoft pour simuler des appels de méthode statiques. (Le framework Fakes a été inclus dans Visual Studio 2012 en tant que successeur de Moles - il s'agit de la prochaine génération de Moles and Stubs.) Une autre façon de simuler les appels de méthode statiques consiste à utiliser des délégués. Il existe encore une autre façon de simuler les appels de méthode statiques dans une application - en utilisant des classes wrapper et une injection de dépendances.

IMHO cette dernière option est la meilleure solution au problème. Tout ce que vous avez à faire est d'encapsuler l'appel de méthode statique dans une méthode d'instance, puis d'utiliser l'injection de dépendances pour injecter une instance de la classe wrapper dans la classe testée.

Créer une classe wrapper en C #

L'extrait de code suivant illustre la classe LogWrapper qui implémente l'interface IWrapper et encapsule un appel à la méthode Logger.Write () dans une méthode d'instance appelée LogData.

classe publique LogWrapper: IWrapper

    {

        chaîne _message = null;

        public LogWrapper (message sous forme de chaîne)

        {

            _message = message;

        }

        public void LogData (message sous forme de chaîne)

        {

            _message = message;

            Logger.Write (_message);

        }

    }

L'extrait de code suivant montre l'interface IWrapper. Il contient la déclaration de la méthode LogData.

interface publique IWrapper

    {

        void LogData (message de chaîne);

    }

La classe ProductBL utilise l'injection de dépendances (injection de constructeur) pour injecter une instance de la classe LogWrapper, comme indiqué dans la liste de codes ci-dessous.

classe publique ProductBL

    {

        readonly IWrapper _wrapper;

        chaîne statique _message = null;

        public ProductBL (wrapper IWrapper)

        {

            _wrapper = wrapper;

        }

        public void LogMessage (message sous forme de chaîne)

        {

            _message = message;

            _wrapper.LogData (_message);

        }

    }

La méthode LogMessage de la classe ProductBL appelle la méthode LogData sur l'instance de la classe LogWrapper qui a été injectée précédemment.

Utilisez xUnit et Moq pour créer une méthode de test unitaire en C #

Ouvrez le fichier UnitTest1.cs et renommez la classe UnitTest1 en UnitTestForStaticMethodsDemo. Les fichiers UnitTest1.cs seraient automatiquement renommés en UnitTestForStaticMethodsDemo.cs. Nous allons maintenant profiter du framework Moq pour configurer, tester et vérifier les simulations.

L'extrait de code suivant illustre comment vous pouvez utiliser le framework Moq pour des méthodes de test unitaire en C #.

var mock = nouveau Mock ();

mock.Setup (x => x.LogData (It.IsAny ()));

nouveau ProductBL (mock.Object) .LogMessage ("Hello World!");

mock.VerifyAll ();

Lorsque vous exécutez le test, voici à quoi doit ressembler la sortie dans la fenêtre de l'Explorateur de tests.

La liste complète des codes de la classe de test est donnée ci-dessous pour votre référence.

classe publique UnitTestForStaticMethodsDemo

    {

        [Fait]

        public void StaticMethodTest ()

        {

            var mock = nouveau Mock ();

            mock.Setup (x => x.LogData (It.IsAny ()));

            nouveau ProductBL (mock.Object) .LogMessage ("Hello World!");

            mock.VerifyAll ();

        }

    }

Le test unitaire est un processus qui teste les unités de code dans une application pour vérifier si les résultats réels de votre test unitaire correspondent aux résultats souhaités. S'ils sont utilisés judicieusement, les tests unitaires peuvent aider à éviter les bogues dans la phase de développement d'un projet.

Les méthodes statiques peuvent poser un certain nombre de problèmes lorsque vous essayez de les tester à l'aide de simulacres. Si votre application vous oblige à vous moquer d'une méthode statique, vous devez considérer qu'une conception sent - c'est-à-dire un indicateur d'une mauvaise conception. Je discuterai des mocks, des faux et des talons plus en détail dans un prochain article ici.

Comment faire plus en C #:

  • Comment refactoriser des objets Dieu en C #
  • Comment utiliser ValueTask en C #
  • Comment utiliser l'immuabilité en C
  • Comment utiliser const, readonly et static en C #
  • Comment utiliser les annotations de données en C #
  • Comment travailler avec les GUID en C # 8
  • Quand utiliser une classe abstraite ou une interface en C #
  • Comment travailler avec AutoMapper en C #
  • Comment utiliser les expressions lambda en C #
  • Comment travailler avec les délégués Action, Func et Predicate en C #
  • Comment travailler avec des délégués en C #
  • Comment implémenter un simple logger en C #
  • Comment travailler avec des attributs en C #
  • Comment travailler avec log4net en C #
  • Comment implémenter le modèle de conception de référentiel en C #
  • Comment travailler avec la réflexion en C #
  • Comment travailler avec Filesystemwatcher en C #
  • Comment effectuer une initialisation différée en C #
  • Comment travailler avec MSMQ en C #
  • Comment travailler avec des méthodes d'extension en C #
  • Comment utiliser les expressions lambda en C #
  • Quand utiliser le mot clé volatile en C #
  • Comment utiliser le mot clé yield en C #
  • Comment implémenter le polymorphisme en C #
  • Comment créer votre propre planificateur de tâches en C #
  • Comment travailler avec RabbitMQ en C #
  • Comment travailler avec un tuple en C #
  • Explorer les méthodes virtuelles et abstraites en C #
  • Comment utiliser l'ORM Dapper en C #
  • Comment utiliser le modèle de conception de poids mouche en C #