66 votes

Test unitaire pour thread safe-ness ?

J’ai écrit une classe et beaucoup de test unitaire, mais je ne rend pas thread safe. Maintenant, je veux pour sécuriser le fil de la classe, mais prouvez-le et utiliser TDD, je veux écrire certains faute de tests unitaires avant de commencer la refactorisation.

Un bon moyen de faire cela ?

Ma première pensée est juste créer quelques threads et les rendre tous utiliser la classe d’une manière dangereuse. Faire cela assez fois avec nombre suffisant de threads et je me dois de le voir sortir.

21voto

Dror Helper Points 15499

Il y a deux produits qui peuvent vous y aider:

Les deux check pour les blocages dans votre code (par l'intermédiaire de l'unité de test) et je pense que les Échecs vérifie les conditions de course.

À l'aide de ces deux outils est facile - vous écrire un simple test de l'unité et de l'exécuter votre code plusieurs fois et vérifier si les blocages/conditions de course est possible dans votre code.

Edit: Google a publié un outil qui vérifie la condition de concurrence dans l'exécution (pas pendant la phase de tests) qui a appelé thread-course-test.
elle ne trouverez pas toutes les conditions de course car il ne s'analyser de l'exécution et non pas tous les scénarios possibles comme l'outil ci-dessus, mais il peut vous aider à trouver la condition de la course dès qu'il arrive.

Mise à jour: Typemock site n'avait plus de lien Racer, et il n'a pas été mis à jour dans les 4 dernières années. Je suppose que le projet a été fermé.

10voto

Max Galkin Points 10116

Le problème est que la plupart des questions multi-threads, comme conditions de course, sont par leur nature non déterministe. Ils pourront compter sur le comportement de matériel dont vous ne pouvez pas peut-être imiter ou un déclencheur.

C’est à dire même si vous faites des essais avec plusieurs threads, ils ne vont pas être constamment échouer si vous avez un défaut dans votre code.

5voto

jerryjvl Points 9310

Notez que Dror la réponse ne disent pas explicitement, mais au moins le jeu d'Échecs (et probablement Racer) le travail à l'exécution d'un ensemble de threads à travers tout leur possible des entrelacements d'obtenir repreoducible erreurs. Ils ne se contentent pas d'exécuter les threads pour un tout en espérant que si il y a une erreur, il va se produire par hasard.

Jeu d'échecs par exemple seront utilisés dans l'ensemble des entrelacements et puis vous donner une étiquette de chaîne de caractères qui représente l'entrelacement qu'un blocage a été trouvé sur de sorte que vous pouvez attribuer vos tests avec des entrelacements qui sont intéressants d'un point de vue de l'interblocage.

Je ne sais pas exactement fonctionnement interne de cet outil, et comment il les cartes de ces étiquette de chaînes de retour de code que vous pouvez être en train de changer pour résoudre une impasse, mais là vous l'avez... je suis vraiment impatient de cet outil (et Pex) de faire partie de la VS IDE.

3voto

daramarak Points 3662

J'ai vu des gens essayer de tester avec la norme unittests comme vous le proposer. Les tests sont lents, et ont jusqu'à présent échoué à identifier un seul de la simultanéité des problèmes de notre société luttes avec.

Après de nombreux échecs, et malgré mon amour pour unittests, je suis venu à accepter que des erreurs dans la simultanéité n'est pas l'un des unittests forces. J'ai l'habitude d'encourager l'analyse et de l'examen en faveur de unittests pour les classes où la simultanéité est un sujet. Avec un total de vue d'ensemble du système, il est dans de nombreux cas, possible de prouver/falsifier les revendications de la sécurité des threads.

En tout cas j'aimerais qu'on me donne quelque chose qui pourrait le contraire, j'ai donc regarder cette question de près.

2voto

Cellfish Points 1708

Quand j'ai récemment eu à traiter le même problème, j'ai pensé à lui de cette façon; tout d'Abord votre classe existante a une responsabilité, c'est de donner à certaines fonctionnalités. Ce n'est pas les objets responsabilité d'être thread-safe. Si elle doit être thread-safe autres objets doivent être utilisés pour fournir cette fonctionnalité. Mais si un autre objet est de fournir à l'thread-safe-ness il ne peut pas être une option, car alors vous ne pouvez pas prouver votre code est thread-safe. Donc, c'est la façon dont je le manipuler:

// This interface is optional, but is probably a good idea.
public interface ImportantFacade
{
    void ImportantMethodThatMustBeThreadSafe();
}

// This class provides the thread safe-ness (see usage below).
public class ImportantTransaction : IDisposable
{
    public ImportantFacade Facade { get; private set; }
    private readonly Lock _lock;

    public ImportantTransaction(ImportantFacade facade, Lock aLock)
    {
        Facade = facade;
        _lock = aLock;
        _lock.Lock();
    }

    public void Dispose()
    {
        _lock.Unlock();
    }
}

// I create a lock interface to be able to fake locks in my tests.
public interface Lock
{
    void Lock();
    void Unlock();
}

// This is the implementation I want in my production code for Lock.
public class LockWithMutex : Lock
{
    private Mutex _mutex;

    public LockWithMutex()
    {
        _mutex = new Mutex(false);
    }

    public void Lock()
    {
        _mutex.WaitOne();
    }

    public void Unlock()
    {
        _mutex.ReleaseMutex();
    }
}

// This is the transaction provider. This one should replace all your
// instances of ImportantImplementation in your code today.
public class ImportantProvider<T> where T:Lock,new()
{
    private ImportantFacade _facade;
    private Lock _lock;

    public ImportantProvider(ImportantFacade facade)
    {
        _facade = facade;
        _lock = new T();
    }

    public ImportantTransaction CreateTransaction()
    {
        return new ImportantTransaction(_facade, _lock);
    }
}

// This is your old class.
internal class ImportantImplementation : ImportantFacade
{
    public void ImportantMethodThatMustBeThreadSafe()
    {
        // Do things
    }
}

L'utilisation de médicaments génériques rend possible l'utilisation d'un faux de verrouillage dans vos tests pour vérifier que le verrou est toujours à prendre lorsqu'une transaction est créée et pas libéré jusqu'à ce que la transaction est éliminé. Maintenant, vous pouvez également vérifier que le verrou est pris lorsque votre méthode est appelée. L'utilisation dans la production de code devrait ressembler à quelque chose comme ceci:

// Make sure this is the only way to create ImportantImplementation.
// Consider making ImportantImplementation an internal class of the provider.
ImportantProvider<LockWithMutex> provider = 
    new ImportantProvider<LockWithMutex>(new ImportantImplementation());

// Create a transaction that will be disposed when no longer used.
using (ImportantTransaction transaction = provider.CreateTransaction())
{
    // Access your object thread safe.
    transaction.Facade.ImportantMethodThatMustBeThreadSafe();
}

En vous assurant que l'ImportantImplementation ne peut pas être créé par quelqu'un d'autre (par exemple la créer dans le fournisseur et d'en faire une classe privée) vous kan maintenant prouver votre classe est thread-safe, puisqu'il ne peut être accédé sans une opération et l'opération prend toujours la serrure lors de leur création et qu'il se dégage lors de son élimination.

Assurez-vous que la transaction est éliminé correctement, peut être plus difficile et si pas, vous risquez de voir des comportements bizarres dans votre application. Vous pouvez utiliser des outils comme Microsoft Échecs (comme suggéré dans un autre anser) à chercher des choses comme ça. Ou vous pouvez avoir votre fournisseur de mettre en œuvre la façade et de la faire appliquer comme ceci:

    public void ImportantMethodThatMustBeThreadSafe()
    {
        using (ImportantTransaction transaction = CreateTransaction())
        {
            transaction.Facade.ImportantMethodThatMustBeThreadSafe();
        }
    }

Même si ce n'est la mise en œuvre, je l'espère, vous pouvez trouver des tests pour vérifier ces classes en tant que de besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X