Question

Nous avons des tests NUnit qui ont accès à la base de données. Lorsque l'un d'entre eux échoue, il peut quitter la base de données dans un état incohérent - qui est pas un problème, puisque nous reconstruisons la base de données pour chaque essai -. Mais il peut provoquer d'autres tests à l'échec dans la même série

Est-il possible de détecter que l'un des tests a échoué et effectuer une sorte de nettoyage?

Nous ne voulons pas d'écrire du code de nettoyage dans tous les tests, nous faisons déjà maintenant. Je voudrais perfrom nettoyage en Teardown mais seulement si le test a échoué, comme le nettoyage peut être coûteux.

Mise à jour : Pour clarifier - Je voudrais des tests pour être simple et ne pas inclure toute logique de gestion du nettoyage ou d'erreurs. Je ne veux pas également effectuer sur chaque base de données remise à zéro essai - que si le test échoue. Et ce code devrait probablement être exécuté dans la méthode TEARDOWN mais je ne suis pas au courant d'aucune façon d'obtenir des informations si le test que nous sommes en train de abattons a réussi ou échoué.

Update2 :

        [Test]
        public void MyFailTest()
        {
            throw new InvalidOperationException();
        }

        [Test]
        public void MySuccessTest()
        {
            Assert.That(true, Is.True);
        }

        [TearDown]
        public void CleanUpOnError()
        {
            if (HasLastTestFailed()) CleanUpDatabase();
        }

Je cherche la mise en œuvre de HasLastTestFailed ()

Était-ce utile?

La solution

Cette idée m'a intéressé, alors je l'ai un peu de creuser. NUnit n'a pas cette capacité de la boîte, mais il y a un cadre fourni avec toute l'extensibilité NUnit. J'ai trouvé ce grand article sur l'extension NUnit - il était un bon point de départ. Après avoir joué avec elle, je suis venu avec la solution suivante: une méthode décorée avec un attribut CleanupOnError personnalisé sera appelé si l'un des tests dans l'appareil a échoué

.

Voilà comment le test ressemble à:

  [TestFixture]
  public class NUnitAddinTest
  {
    [CleanupOnError]
    public static void CleanupOnError()
    {
      Console.WriteLine("There was an error, cleaning up...");
      // perform cleanup logic
    }

    [Test]
    public void Test1_this_test_passes()
    {
      Console.WriteLine("Hello from Test1");
    }

    [Test]
    public void Test2_this_test_fails()
    {
      throw new Exception("Test2 failed");
    }

    [Test]
    public void Test3_this_test_passes()
    {
      Console.WriteLine("Hello from Test3");
    }
  }

où l'attribut est simplement:

  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
  public sealed class CleanupOnErrorAttribute : Attribute
  {
  }

Et voici comment il est exécuté à partir du Addin:

public void RunFinished(TestResult result)
{
  if (result.IsFailure)
  {
    if (_CurrentFixture != null)
    {
      MethodInfo[] methods = Reflect.GetMethodsWithAttribute(_CurrentFixture.FixtureType,
                                                             CleanupAttributeFullName, false);
      if (methods == null || methods.Length == 0)
      {
        return;
      }

      Reflect.InvokeMethod(methods[0], _CurrentFixture);
    }
  }
}

Mais voici la partie la plus délicate: la Addin doit être placé dans le répertoire addins à côté du coureur NUnit. Le mien a été placé à côté du coureur NUnit dans le répertoire TestDriven.NET:

  

C:\Program Files\TestDriven.NET 2.0\NUnit\addins

(j'ai créé le répertoire addins, il était pas là)

EDIT Une autre chose est que la méthode de nettoyage doit être static!

Je piraté ensemble un Addin simple, vous pouvez télécharger la source mon SkyDrive. Vous devrez ajouter des références à nunit.framework.dll, nunit.core.dll et nunit.core.interfaces.dll dans les endroits appropriés.

Quelques notes: La classe d'attribut peut être placé n'importe où dans votre code. Je ne voulais pas le placer dans le même ensemble que l'Addin lui-même, car il fait référence à deux assemblées Core NUnit, donc je l'ai placé dans un assemblage. Rappelez-vous de changer la ligne dans le CleanAddin.cs, si vous décidez de le mettre ailleurs.

L'espoir qui aide.

Autres conseils

Depuis la version 2.5.7, NUnit permet Teardown de détecter si le dernier test a échoué. Une nouvelle classe TestContext permet d'accéder à des tests d'informations sur eux-mêmes, y compris les TestStauts.

Pour plus de détails, s'il vous plaît se référer à http://nunit.org/?p=releaseNotes&r = 2.5.7

[TearDown]
public void TearDown()
{
    if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)
    {
        PerformCleanUpFromTest();
    }
}

Alors qu'il pourrait être possible de forcer nUnit en ce faisant, il n'est pas la conception la plus sensible, vous pouvez toujours définir un fichier temporaire quelque part et si ce fichier existe, exécutez votre nettoyage.

Je recommande de changer votre code afin que vous avez la base de données transactions permis et à la fin du test, revenez simplement la base de données à l'état d'origine (par exemple jeter la transaction qui représente vos tests unitaires).

Oui, il y a. Vous pouvez utiliser le Teardown attribut qui sera tearDown après chaque test. Vous voudriez appliquer cette base de données script « reset » que vous avez et désassemblage et re-configuration avant et après chaque test.

  

Cet attribut est utilisé dans un   TestFixture de fournir un ensemble commun de   les fonctions qui sont exécutées après   chaque méthode d'essai est exécuté.

Mise à jour : Sur la base des commentaires et mise à jour à la question, je dirais que vous pouvez utiliser l'attribut et teardown utiliser des variables privées pour indiquer si le contenu doit tirer de la méthode.

Bien, je ne aussi que vous ne voulez pas de code de traitement logique ou erreur complexe.

Étant donné que, je pense qu'une norme d'installation / Teardown serait le mieux pour vous. Peu importe s'il y a une erreur et que vous ne devez pas avoir un code de gestion des erreurs.

Si vous devez nettoyer spécial parce que les prochains essais dépend de la réussite du test en cours, je vous suggère de revoir vos tests -. Ils ne devraient probablement pas dépendre de l'autre

Qu'en est-il avec un bloc try-catch, rethrowing l'exception pris?

try
{
//Some assertion
}
catch
{
     CleanUpMethod();
     throw;
}

Je ferais comme phsr suggère pour l'instant et quand vous pouvez vous le permettre, factoriser les essais afin qu'ils aient jamais compter sur les mêmes données que l'autre a besoin de test ou encore mieux abstraite la couche d'accès aux données et railler les résultats provenant de cette base de données. On dirait que vos tests sont assez chers et vous vous devez faire tout votre logique de requête sur la base de données et la logique métier dans votre assemblée vous ne se soucient pas vraiment ce que les résultats sont renvoyés.

Vous pourrez également tester votre ExceptionHandling beaucoup mieux.

Une autre option est d'avoir une fonction spéciale qui jetteront vos exceptions, qui définit un interrupteur dans le TestFixture qui dit une exception est survenue.

public abstract class CleanOnErrorFixture
{
     protected bool threwException = false;

     protected void ThrowException(Exception someException)
     {
         threwException = true;
         throw someException;
     }

     protected bool HasTestFailed()
     {
          if(threwException)
          {
               threwException = false; //So that this is reset after each teardown
               return true;
          }
          return false;
     }
}

Ensuite, en utilisant votre exemple:

[TestFixture]
public class SomeFixture : CleanOnErrorFixture
{
    [Test]
    public void MyFailTest()
    {
        ThrowException(new InvalidOperationException());
    }

    [Test]
    public void MySuccessTest()
    {
        Assert.That(true, Is.True);
    }

    [TearDown]
    public void CleanUpOnError()
    {
        if (HasLastTestFailed()) CleanUpDatabase();
    }
}

Le seul problème ici est que la trace de la pile conduira à la CleanOnErrorFixture

Une option non mentionnée jusqu'à présent est d'envelopper le test dans un objet TransactionScope, donc peu importe ce qui se passe que le test ne commet jamais rien à la DB.

Voici quelques détails sur la technique . Vous pouvez probablement plus si vous effectuez une recherche sur les tests unitaires et TransactionScope (bien que vous faites vraiment des tests d'intégration si vous frappez un DB). Je l'ai utilisé avec succès dans le passé.

Cette approche est simple, ne nécessite aucun nettoyage et assure que les tests sont isolés.

Modifier- Je viens de remarquer réponse Ray Hayes est également similaire à la mienne.

Comment échouer? Est-il possible de le mettre dans un essai (faire test) / catch (db fixer cassé) / finally?

Ou vous pourriez appeler une méthode privée pour le corriger lorsque vous avez vérifié votre échec état.

Je ne dis pas cela est une excellente idée, mais il devrait fonctionner. Rappelez-vous que les erreurs d'assertion ne sont que des exceptions. De plus, ne pas oublier qu'il ya aussi un [TestFixtureTearDown] attribut qui passe juste une fois après avoir tous les tests dans l'appareil.

En utilisant ces deux faits que vous pouvez écrire quelque chose comme la fixation d'un drapeau si un échec des tests et la vérification de la valeur du drapeau dans le dispositif d'essai abattez.

Je ne recommande pas, mais ça marcherait. Vous n'êtes pas vraiment utiliser NUnit comme prévu, mais vous pouvez le faire.


[TestFixture]
public class Tests {
     private bool testsFailed = false;

     [Test]
     public void ATest() {
         try {
             DoSomething();
             Assert.AreEqual(....);
         } catch {
            testFailed = true;
         }
     }

     [TestFixtureTearDown]
     public void CleanUp() {
          if (testsFailed) {
              DoCleanup();
          }
     }
}

Vous pouvez ajouter une méthode de [TearDown] avec
if (TestContext.CurrentContext.Result.Status != TestStatus.Passed)
un code à exécuter si le test a échoué.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top