2008-10-20 8 views
0

J'écris un test qui s'attend à recevoir un événement d'un objet qu'il appelle. Plus précisément, j'appelle à un objet qui se connecte à une machine AIX via SSH (en utilisant le projet open source Granados), puis déconnecte, et je veux m'assurer de recevoir l'événement OnConnectionClosed qui est levé pendant la déconnexion. Cela semble assez simple, et j'ai écrit de nombreux tests comme celui-ci dans le passé, mais cette fois, il se produit un comportement étrange qui, je crois, est lié au threading.Comment écrire un test d'unité MSTest à l'écoute d'un événement à déclencher à partir d'un autre thread?

Fondamentalement, l'objet que j'appelle soulève l'événement 'OnConnectionClosed' sur un thread différent de celui que je l'appelle. Ce que je vois, c'est que quand j'exécute le test en sélectionnant 'Test de débogage', ça passe, mais si je choisis 'Exécuter Test', ça échoue (même s'il n'y a pas de points d'arrêt pendant le débogage). J'ai fait un peu de Googling et trouvé this post qui semble indiquer que par défaut l'hôte MSTest s'exécute en mode Single Thread mais qu'un changement de configuration peut le faire fonctionner en mode Multi Thread. Cela sonnait comme si cela réglerait logiquement mon problème, mais bien sûr, ce n'était pas le cas. Certains autres messages que j'ai rencontrés me font penser que MSTest ne surveille tout simplement pas les threads d'arrière-plan (donc les événements qu'ils soulèvent ne sont pas 'entendus'). Cela aurait également du sens, et comme il semble fonctionner en mode débogage, et il semble que le correctif ci-dessus devrait logiquement résoudre ce problème, alors je suis confus quant à savoir pourquoi cela ne fonctionne pas. Il est possible que je ne traite pas correctement les threads, bien que je m'attendrais à ce que ce soit encore un problème en mode debug si c'était le cas.

Est-ce que quelqu'un d'autre a essayé de tester quelque chose d'une manière similaire? Si oui, avez-vous rencontré des problèmes similaires? Et si oui, comment les avez-vous résolus?

J'ai collé le code de test unitaire pertinent ci-dessous (j'ai supprimé les informations de connexion pour des raisons de sécurité).

[TestClass] 
public class SSHReaderTests 
{ 
    private bool received = false; 
    private delegate bool SimpleFunc(); 

    [TestInitialize] 
    public void MyTestInitialize() 
    { 
     received = false; 
    } 

    [TestMethod] 
    public void Should_raise_OnReaderConnectionClosed_event_after_successful_connection_is_disconnected() 
    { 
     IReader reader = new SSHReader(); 

     reader.OnReaderConnectionClosed += delegate 
            { 
             received = true; 
            }; 

     reader.Connect("*****", "*****", "*****"); 

     //Assert.IsTrue(reader.IsConnected); 

     reader.Disconnect(); 

     //Assert.IsFalse(reader.IsConnected); 

     Assert.IsTrue(WaitUntilTrue(delegate { 
      return received; }, 30000, 1000)); 
    } 

    private static bool WaitUntilTrue(SimpleFunc func, int timeoutInMillis, int timeBetweenChecksInMillis) 
    { 
     Stopwatch stopwatch = new Stopwatch(); 
     stopwatch.Start(); 

     while(stopwatch.ElapsedMilliseconds < timeoutInMillis) 
     { 
      if (func()) 
       return true; 

      Thread.Sleep(timeBetweenChecksInMillis); 
     } 
     return false; 
    } 
} 

Répondre

2

Utilisez les classes WaitHandle dans l'espace de noms System.Threading. Soit, AutoResetEvent ou ManualResetEvent. La différence entre les deux est que AutoResetEvent permet à un thread de continuer à chaque fois qu'il est défini, tandis que ManualResetEvent libère tous les threads en attente sur set.

La raison pour laquelle votre exemple ne fonctionne pas concerne les optimisations du compilateur. Le code n'est pas vraiment compilé à ce que vous pourriez penser à première vue. Très probablement, le compilateur fera quelque chose comme placer la variable locale dans un registre et ne jamais le récupérer pendant votre boucle qui vérifie. Vous pouvez éviter ce type de chose avec le mot-clé volatile, mais je vous recommande fortement de lire sur le threading et la concurrence pour plus de détails. Le blog de Joe Duffy au http://www.bluebytesoftware.com est une excellente ressource pour commencer, et je recommande fortement son livre Concurrency Programming sur Windows qui sort bientôt.

0

Pas exactement ce que vous demandez, mais vous pouvez trouver des solutions réalisables ou au moins des idées en consultant le projet MS Research appelé CHESS. C'est pour le test de simultanéité multithread dans .net.

Questions connexes