2009-09-28 6 views
6

J'écris une suite de tests unitaires pour tester une bibliothèque de communication TCP/IP. Lorsque j'utilise BeginAcceptClient et EndAcceptClient, les messages sont reçus dans un thread d'arrière-plan.Comment gérer l'exception dans un thread d'arrière-plan dans un test unitaire?

Après la réception d'un message, j'effectue certaines assertions, mais si une assertion échoue, le VSTestHost.exe se bloque. Je ai googlé un peu et a découvert le fait que les exceptions Assert sont lancées dans un fil de fond.

EDIT: Un exemple de code de ce que je fais, juste à illustrer:


public void TestFooMessage() { 
    Server.OnReceive += (s, e) => { 
     Assert.IsInstanceOfType(e.Message, typeof(Foo)); 
    }; 

    var message = new Foo(); 
    Client.Send(message); 
} 

Est-ce que quelqu'un sait comment faire fonctionner comme prévu: Connectez-vous l'affirmation et continue de fonctionner normalement?

Répondre

6

Vous ne devriez pas écrire le Affirme dans le fil de fond (par exemple: le gestionnaire d'événements d'arrière-plan), car le framework de test ne peut pas gérer cela. Vous devriez seulement rassembler des valeurs là-bas. Vous pouvez synchroniser le thread principal par exemple en utilisant AutoResetEvents. Ecrire les valeurs dans les champs, affirmer les champs dans le fil principal.

Si les messages n'arrivent jamais, vous avez besoin d'un délai d'expiration.

Un code binaire pseudo (en fait pas de pseudo):

private AutoResetEvent ReceiveEvent = new AutoResetEvent(false); 
private EventArgs args; 
private bool ReceiveCalled = false; 

// event handler with some argument 
private void Receive(object sender, EventArgs args) 
{ 
    // get some arguments from the system under test 
    this.args= args; 

    // set the boolean that the message came in 
    ReceiveCalled = true; 

    // let the main thread proceed 
    ReceiveEvent.Set(); 
} 

[TestMethod] 
public void Test() 
{ 
    // register handler 
    Server.OnReceive += Receive; 

    var message = new Foo(); 
    Client.Send(message); 

    // wait one second for the messages to come in 
    ReceiveEvent.WaitOne(1000); 

    // check if the message has been received 
    Assert.IsTrue(
    ReceiveCalled, 
    "AcceptClientReceived has not been called"); 

    // assert values from the message 
    Assert.IsInstanceOfType(args.Message, typeof(Foo))  
} 

A propos: vous pouvez toujours écrire le gestionnaire comme une expression lambda et même éviter les champs en utilisant des variables locales. Mais il pourrait être plus difficile à lire si tout est dans une seule méthode.

1

Je suppose que vous aurez essentiellement besoin d'une sorte de drapeau « tout va bien »:

  1. Créer ce drapeau et mettez-le à vrai au début du test
  2. Ecrivez une méthode Assert parallèle qui efface le drapeau et définit peut-être une autre variable pour la "raison" (ou l'ajoute à une liste) puis quitte le thread proprement (si possible)
  3. Faire le thread de test principal attendre que tous les autres threads se terminent, puis vérifier le drapeau.

Il est possible que certains cadres de test ont intégré, mais je ne connais pas de désinvolture ...

+1

Le problème est que les threads sont créés par le système testé. En général, vous ne les connaissez même pas, sauf si vous êtes rappelé. Il n'y a pas de solution générale pour les threads d'arrière-plan dans les tests unitaires. –

+1

Attendre un événement dans la fonction de test et définir l'événement dans le rappel asynchrone. –

0

J'ai essayé ce que Stefan a suggéré, et les travaux suivants pour moi:

public void TestFooMessage() { 
    Foo message = null; 
    var resetEvent = new AutoResetEvent(false); 

    Server.OnReceive += (s, e) => { 
     message = e.Message; 
     resetEvent.Set(); 
    }; 

    var message = new Foo(); 
    Client.Send(message); 

    if (resetEvent.WaitOne(1000)) { 
     Assert.IsInstanceOfType(e.Message, typeof(Foo)); 
    } else { 
     Assert.Fail("Foo not received!"); 
    } 
} 

Merci!

Questions connexes