Question

J'utilise C # 3.0 et NUnit. Je me demande s'il existe un moyen standard d'exécuter des tests unitaires sur du code qui s'exécute après un certain temps. Par exemple, j'ai une classe statique simple avec laquelle je peux enregistrer des méthodes et les faire appeler n millisecondes plus tard. Je dois m'assurer que le code des méthodes de délégation est appelé.

Par exemple, le test suivant réussira toujours, car aucune assertion n’a été effectuée avant la fin de la méthode.

[Test]
public void SampleTest()
{
    IntervalManager.SetTimeout(delegate{ 
        Assert.Equals(now.Millisecond + 100, DateTime.Now.Millisecond); 
    }, 100);
}

Est-il même possible de code de test unitaire qui ne s'exécute pas immédiatement?

A bientôt,

Paul

Était-ce utile?

La solution

Comment ça? Cela a pour effet de bloquer le test pendant un certain temps maximum prévu pour le rappel et de le terminer avant le retrait, en signalant une erreur.

public void Foo() {
    AutoResetEvent evt = new AutoResetEvent(false);
    Timer t = new Timer(state => {
        // Do work
        evt.Set();
    }, null, 100, Timeout.Infinite);
    if (evt.WaitOne(500)) {
        // method called and completed
    } else {
        // timed out waiting
    }
}

Autres conseils

Alors, que testez-vous exactement? Testez-vous que les minuteries fonctionnent? Ou que votre code configure correctement un minuteur de sorte que, à l'expiration du délai, le minuteur exécute un rappel? Sans savoir à quoi ressemble le code, je suppose que ce que vous voulez vraiment tester est ce dernier. Ma réponse serait que (1) cela va probablement être difficile avec des méthodes statiques et (2) vous devrez probablement utiliser l'injection de dépendance et injecter les minuteries simulées, etc. qui n'exécutent pas réellement la méthode résultante, mais enregistrez en espérant que votre code appelle les appels appropriés.

Comme note de côté. Nous essayons généralement de marquer nos tests lents avec une catégorie NUnit et pouvez choisir de passer ces tests sur certaines versions.

Oui, le faire comme dans votre exemple ne fonctionnera pas.

Je vous recommanderais plutôt de créer une classe de test à utiliser en tant que délégué, qui enregistre quand sa méthode a été appelée et à quelle heure.

Vous injectez ensuite votre maquette dans l'IntervalManager que vous souhaitez tester. Votre méthode de test doit alors attendre IntervalManager (à l’aide d’une méthode appropriée fournie par IntervalManager, ou simplement attendre quelques secondes). Vous pourrez ensuite vérifier l’état de la classe de test.

BTW, cette approche est généralement appelée moqueur ; dans ce cas, la classe de test serait l'objet fictif.

Comme l'ont indiqué quelques autres réponses, les tests de longue durée sont généralement une mauvaise idée. Pour faciliter le test de ce composant, vous devez considérer que vous essayez réellement de tester deux choses distinctes.

  1. Lorsque vous enregistrez une exécution de délégué chronométré, l'heure correcte est définie. Cela devra probablement être testé avec différentes combinaisons de délais d'attente et de nombres de délégués.
  2. Le délégué est exécuté correctement.

En séparant les tests de la manière suivante, vous pourrez vérifier que votre mécanisme de chronométrage fonctionne comme prévu avec un petit nombre de délais rapides (testant tous les cas à prendre en compte). N'oubliez pas que vous aurez probablement besoin d'un peu de marge de manœuvre pendant le temps nécessaire pour exécuter un délégué donné en fonction de la charge actuelle sur le système et de la complexité du code de votre composant (dans IntervalManager ).

Bien sûr, vous pouvez le tester. Vous devez juste attendre son exécution.

Il se peut que quelque chose me manque, mais les tests unitaires de Visual Studio possèdent des attributs spéciaux que vous pouvez définir pour les méthodes de contrôle de l'ordre d'exécution et autres. Cela aurait dû être généré automatiquement lorsque vous avez créé le projet de tests unitaires:

    #region Additional test attributes
    // 
    //You can use the following additional attributes as you write your tests:
    //
    //Use ClassInitialize to run code before running the first test in the class
    //[ClassInitialize]
    //public static void MyClassInitialize(TestContext testContext) {
    //}
    //
    //Use ClassCleanup to run code after all tests in a class have run
    //[ClassCleanup()]
    //public static void MyClassCleanup()
    //{
    //}
    //
    //Use TestInitialize to run code before running each test
    //[TestInitialize()]
    //public void MyTestInitialize()
    //{
    //}
    //
    //Use TestCleanup to run code after each test has run
    //[TestCleanup()]
    //public void MyTestCleanup()
    //{
    //}
    //
    #endregion

Donc, utiliser [ClassInitialize] devrait vous permettre d'écrire tout ce qui doit être exécuté en premier dans une méthode. Ensuite, vos tests peuvent être exécutés. Ou vous pouvez utiliser [TestInitialize] pour exécuter le code avant chaque test.

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