Unit test for thread safe-ness?

后端 未结 9 1774
你的背包
你的背包 2020-11-30 19:32

I\'ve written a class and many unit test, but I did not make it thread safe. Now, I want to make the class thread safe, but to prove it and use TDD, I want to write some fa

9条回答
  •  独厮守ぢ
    2020-11-30 19:48

    Though it's not as elegant as using a tool like Racer or Chess, I have used this sort of thing for testing for thread safety:

    // from linqpad
    
    void Main()
    {
        var duration = TimeSpan.FromSeconds(5);
        var td = new ThreadDangerous(); 
    
        // no problems using single thread (run this for as long as you want)
        foreach (var x in Until(duration))
            td.DoSomething();
    
        // thread dangerous - it won't take long at all for this to blow up
        try
        {           
            Parallel.ForEach(WhileTrue(), x => 
                td.DoSomething());
    
            throw new Exception("A ThreadDangerException should have been thrown");
        }
        catch(AggregateException aex)
        {
            // make sure that the exception thrown was related
            // to thread danger
            foreach (var ex in aex.Flatten().InnerExceptions)
            {
                if (!(ex is ThreadDangerException))
                    throw;
            }
        }
    
        // no problems using multiple threads (run this for as long as you want)
        var ts = new ThreadSafe();
        Parallel.ForEach(Until(duration), x => 
            ts.DoSomething());      
    
    }
    
    class ThreadDangerous
    {
        private Guid test;
        private readonly Guid ctrl;
    
        public void DoSomething()
        {           
            test = Guid.NewGuid();
            test = ctrl;        
    
            if (test != ctrl)
                throw new ThreadDangerException();
        }
    }
    
    class ThreadSafe
    {
        private Guid test;
        private readonly Guid ctrl;
        private readonly object _lock = new Object();
    
        public void DoSomething()
        {   
            lock(_lock)
            {
                test = Guid.NewGuid();
                test = ctrl;        
    
                if (test != ctrl)
                    throw new ThreadDangerException();
            }
        }
    }
    
    class ThreadDangerException : Exception 
    {
        public ThreadDangerException() : base("Not thread safe") { }
    }
    
    IEnumerable Until(TimeSpan duration)
    {
        var until = DateTime.Now.Add(duration);
        ulong i = 0;
        while (DateTime.Now < until)
        {
            yield return i++;
        }
    }
    
    IEnumerable WhileTrue()
    {
        ulong i = 0;
        while (true)
        {
            yield return i++;
        }
    }
    

    The theory is that if you can cause a thread dangerous condition consistently to occur in a very short amount of time, you should be able to bring about thread safe conditions and verify them by waiting a relatively large amount of time without observing state corruption.

    I do admit that this may be a primitive way of going about it and may not help in complex scenarios.

提交回复
热议问题