136 votes

Exécuter le code une fois avant et après TOUS les tests dans xUnit.net

TL;DR - Je cherche l'équivalent pour xUnit de la fonction MSTest. AssemblyInitialize (c'est-à-dire la seule caractéristique que j'apprécie).

Plus précisément, je la recherche parce que j'ai quelques tests Selenium smoke que j'aimerais pouvoir exécuter sans autres dépendances. J'ai un Fixture qui lance IisExpress pour moi et le tue au moment de l'élimination. Mais faire cela avant chaque test gonfle énormément le temps d'exécution.

Je voudrais déclencher ce code une fois au début du test, et le détruire (en arrêtant le processus) à la fin. Comment puis-je m'y prendre ?

Même si je peux obtenir un accès programmatique à quelque chose comme "combien de tests sont en cours d'exécution", je peux trouver une solution.

99voto

gzou Points 344

Depuis Nov 2015, xUnit 2 est sorti, il y a donc un moyen canonique de partager des fonctionnalités entre les tests. Elle est documentée aquí .

En gros, vous devrez créer une classe pour effectuer le montage :

    public class DatabaseFixture : IDisposable
    {
        public DatabaseFixture()
        {
            Db = new SqlConnection("MyConnectionString");

            // ... initialize data in the test database ...
        }

        public void Dispose()
        {
            // ... clean up test data from the database ...
        }

        public SqlConnection Db { get; private set; }
    }

Une classe fictive portant le nom CollectionDefinition attribut. Cette classe permet à Xunit de créer une collection de tests, et utilisera le fixture donné pour toutes les classes de test de la collection.

    [CollectionDefinition("Database collection")]
    public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
    {
        // This class has no code, and is never created. Its purpose is simply
        // to be the place to apply [CollectionDefinition] and all the
        // ICollectionFixture<> interfaces.
    }

Ensuite, vous devez ajouter le nom de la collection sur toutes vos classes de test. Les classes de test peuvent recevoir le fixture par le biais du constructeur.

    [Collection("Database collection")]
    public class DatabaseTestClass1
    {
        DatabaseFixture fixture;

        public DatabaseTestClass1(DatabaseFixture fixture)
        {
            this.fixture = fixture;
        }
    }

C'est un peu plus verbeux que MsTests AssemblyInitialize puisque vous devez déclarer sur chaque classe de test à quelle collection de tests elle appartient, mais c'est aussi plus modulable (et avec MsTests vous devez toujours mettre une TestClass sur vos classes)

Note : les échantillons ont été prélevés sur le documentation .

56voto

Rolf Kristensen Points 1326

Pour exécuter du code à l'initialisation de l'assemblage, on peut faire ceci (testé avec xUnit 2.3.1)

using Xunit.Abstractions;
using Xunit.Sdk;

[assembly: Xunit.TestFramework("MyNamespace.MyClassName", "MyAssemblyName")]

namespace MyNamespace
{   
   public class MyClassName : XunitTestFramework
   {
      public MyClassName(IMessageSink messageSink)
        :base(messageSink)
      {
        // Place initialization code here
      }

      public new void Dispose()
      {
        // Place tear down code here
        base.Dispose();
      }
   }
}

Voir aussi https://github.com/xunit/samples.xunit/tree/master/AssemblyFixtureExample

30voto

Jared Kells Points 1604

Créez un champ statique et implémentez un finaliseur.

Vous pouvez utiliser le fait que xUnit crée un AppDomain pour exécuter votre assemblage de test et le décharge lorsqu'il est terminé. Le déchargement du domaine d'application entraînera l'exécution du finalisateur.

J'utilise cette méthode pour démarrer et arrêter IISExpress.

public sealed class ExampleFixture
{
    public static ExampleFixture Current = new ExampleFixture();

    private ExampleFixture()
    {
        // Run at start
    }

    ~ExampleFixture()
    {
        Dispose();
    }

    public void Dispose()
    {
        GC.SuppressFinalize(this);

        // Run at end
    }        
}

Edit : Accédez au dispositif en utilisant ExampleFixture.Current dans vos tests.

19voto

Brad Wilson Points 22910

Ce n'est pas possible de le faire dans le cadre actuel. Il s'agit d'une fonctionnalité prévue pour la version 2.0.

Pour que cela fonctionne avant la version 2.0, il vous faudrait procéder à une ré-architecture importante du framework, ou écrire vos propres runners qui reconnaissent vos propres attributs spéciaux.

5voto

Shimmy Points 23393

J'utilise MontageFixation ( NuGet ).

Ce qu'il fait, c'est qu'il fournit une IAssemblyFixture<T> qui remplace toute interface IClassFixture<T> où vous voulez que la durée de vie de l'objet soit celle de l'assemblage de test.

Exemple :

public class Singleton { }

public class TestClass1 : IAssemblyFixture<Singleton>
{
  readonly Singletone _Singletone;
  public TestClass1(Singleton singleton)
  {
    _Singleton = singleton;
  }

  [Fact]
  public void Test1()
  {
     //use singleton  
  }
}

public class TestClass2 : IAssemblyFixture<Singleton>
{
  readonly Singletone _Singletone;
  public TestClass2(Singleton singleton)
  {
    //same singleton instance of TestClass1
    _Singleton = singleton;
  }

  [Fact]
  public void Test2()
  {
     //use singleton  
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X