J'ai une méthode qui contient un appel asynchrone comme celui-ci:Comment puis-je tester une méthode contenant un appel asynchrone?
public void MyMethod() {
...
(new Action<string>(worker.DoWork)).BeginInvoke(myString, null, null);
...
}
J'utilise l'unité et la création d'objets fantaisie ne sont pas un problème, mais comment puis-je vérifier que DoWork est appelé sans se soucier des conditions de course?
Un previous question offre une solution, mais il me semble que wait-handles est un hack (la condition de course est toujours là, bien qu'il devrait être pratiquement impossible à élever).
EDIT: D'accord, je pensais que je pourrais poser cette question d'une manière très générale, mais il semble que je dois élaborer davantage sur le problème:
Je veux créer un test pour mentionné ci-dessus MyMethod, donc je fais quelque chose comme ceci:
[TestMethod]
public void TestMyMethod() {
...setup...
MockWorker worker = new MockWorker();
MyObject myObj = new MyObject(worker);
...assert preconditions...
myObj.MyMethod();
...assert postconditions...
}
L'approche naïve serait de créer un MockWorker() qui définit simplement un drapeau quand DoWork a été appelé, et vérifier que le drapeau dans les postconditions. Cela conduirait bien sûr à une condition de concurrence, où les postconditions sont vérifiées avant que le drapeau ne soit placé dans le MockWorker.
L'approche la plus correcte (que je vais probablement à l'aide) avec une attente poignée:
... et utiliser l'affirmation suivante:
Assert.IsTrue(worker.AutoResetEvent.WaitOne(1000, false));
C'est en utilisant une approche de type sémaphore, ce qui est bien ... mais dans la théorie ce qui pourrait arriver:
- BeginInvoke est appelée sur mon délégué DoWork
- Pour une raison quelconque, le thread principal ou le thread DoWork ne reçoit pas de temps d'exécution de 1000ms.
- Le thread principal reçoit un temps d'exécution, et en raison du délai d'attente, l'assertion échoue, même si le thread DoWork doit encore être exécuté.
Ai-je mal compris comment fonctionne AutoResetEvent? Suis-je juste trop paranoïaque, ou y a-t-il une solution intelligente à ce problème?
Pouvez-vous expliquer les conditions de concurrence dans cette situation? C'est à peu près la solution que j'utilise et ça ne m'a jamais manqué. –
Non, je suis sûr que ça n'échoue jamais, parce que la condition de la course est principalement théorique. La condition de concurrence est simple: si, pour une raison quelconque, le thread de travail ne reçoit jamais de temps d'exécution avant le timeout, le test échoue à tort. Je sais! C'est spéculatif, mais je connais la loi de Murphy ;-) – toxvaerd
J'ai vu des tests qui utilisaient des drapeaux comme ceux-ci échouer sur des serveurs de build lourdement chargés (nécessitant des reconstructions qui ajoutent à la charge). Aller sur la route de signalisation et utiliser un timeout me semble mieux. En outre, l'utilisation de drapeaux signifie que vous devez dormir pendant toute la période, ce qui peut rendre votre suite de tests beaucoup plus longue que nécessaire. –