2010-12-14 37 views
8

En utilisant mon application, je suis tombé sur une condition de concurrence dans un code qui utilise un NSOperationQueue pour exécuter des tâches de manière asynchrone suite à des événements déclenchés par l'utilisateur. Je sais comment réparer la condition de concurrence, car c'est une erreur de conception stupide que je ne vais pas approfondir, mais je voudrais prouver le bug avec un cas de test (pour qu'il ne revienne pas lors de l'optimisation/refactoring sur toute la ligne). Cela m'a bloqué. Comment va-t-on tester quelque chose qui est multi-thread, surtout quand le but du test est de générer une condition de concurrence?Unité testant le code basé sur le thread? Forcer une condition de concurrence

Quelqu'un a-t-il des liens vers du matériel de référence auquel je peux me référer lorsqu'il est question de threads et de tests unitaires? Je suis particulièrement intéressé par la génération de conditions de course.

+0

Je suppose que vous vous moquez de toutes les structures de données partagées, et à l'intérieur de vos objets simulés vous pouvez effectuer toute la synchronisation dont vous avez besoin pour que les différents threads s'exécutent dans le «mauvais» ordre. –

Répondre

4

Vous devez vous assurer que la séquence d'événements causant la condition de concurrence se produit réellement pendant le test. Pour cela, vous devez affecter l'entrelacement des threads dans le scénario de test.

Vous pouvez réaliser cela avec une synchronisation supplémentaire (conditionnelle) ou des temporisations supplémentaires (plus simples et moins fiables). Mettez des appels sleep() dans les sections critiques pour vous assurer qu'ils s'exécutent suffisamment longtemps pour que l'autre thread arrive dans l'état indésirable. Lorsque vous avez ce travail, remplacez les appels de sommeil par une synchronisation explicite (c'est-à-dire, bloquez un thread jusqu'à ce que l'autre sache qu'il est arrivé).

Ensuite, conditionnez-le à l'aide d'un indicateur global défini par le scénario de test.

+3

Honnêtement, je ne pense pas étroitement couplant le code de production réel à ce test particulier est une bonne idée. Cela signifie que vous devez faire attention de ne pas perturber ce couplage à chaque fois que vous refactorisez le code, ce qui ne permet pas d'avoir ce test en premier lieu. –

+0

Non, la fragilité par rapport à. refactoring prend en charge cette approche de test. Quand vous refactoriserez, vous devrez repenser les conditions de course. Ensuite, vous pouvez constater que le refactoring a réellement introduit de nouveaux, ou que ceux auxquels il était auparavant vulnérable ne peuvent plus se produire. –

+0

Je ne vois tout simplement pas en quoi cela contraindrait quiconque à refondre les conditions de course potentielles, ou que cela serait vraiment utile. Clairement, penser aux conditions de course n'a pas fonctionné la première fois. Toute personne qui refactorise le code de manière significative devrait soit jeter le code de test existant entièrement et en écrire de nouveaux, soit rendre le code de test inutile. De toute façon, cela va à l'encontre du but du code de test. Il serait préférable d'avoir un code de test qui ne pollue pas la base de code principale mais qui marque plutôt la construction comme étant cassée si c'est le cas. –