Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I unit test a lock statement?

How would I write a unit test to ensure that a lock was acquired?

For example:

public void AddItem(object item)
{
    lock (_list)
    {
        _list.Add(item)
    }
}

Is there a way to ensure that the lock statement is run?

Edit: I'm not trying to prove thread-safety (this I would assume), just that the lock() statement is called.

For example, I might test a new object() statement by substituting it in a CreateObject() factory function.

like image 260
g t Avatar asked May 30 '12 13:05

g t


3 Answers

Unit-testing multiple threads is always tricky and should be approached with care.

In your case I wouldn't bother testing lock keyword, for the same reason you don't write tests for new.

Assert.IsNotNull(new object());

Also, you seem to be encapsulating as thread-unsafe collection in order to make it thread-safe. Instead of reinventing the wheel consider using thread-safe collections.

like image 150
Jakub Konecki Avatar answered Oct 14 '22 06:10

Jakub Konecki


The same way you test any other thing: write a test that fails without it. In other words, determine why you are writing the lock in the first place, and write a test that specifies that reason. I assume the reason is thread-safety: if so, write the multi-thread test. If it is some other reason, right that test.

If you really, really want to test calling the lock but not the behavior the lock causes, encapsulate:

public class MyLock : IDisposable
{
    private object _toLock;

    public MyLock(object toLock)
    {
        _toLock = toLock;
        Monitor.Enter(_toLock);
    }

    public virtual void Dispose()
    {
        Monitor.Exit(_toLock);
    }
}

You'll have to make a mockable factory too, of course. Seems like overdoing it to me, but maybe it makes sense in your context.

like image 4
tallseth Avatar answered Oct 14 '22 07:10

tallseth


See Jon Skeet's answer to a similar question: How to test if a thread is holding a lock on an object in C#?:

I don't believe there is. There are grotty hack things you could do like calling Monitor.Wait(monitor, 0) and catching the SynchronizationLockException, but that's pretty horrible (and could theoretically "catch" a pulse that another thread was waiting for). EDIT: In .NET 4.5, this is available with Monitor.IsEntered.

like image 4
SimonC Avatar answered Oct 14 '22 07:10

SimonC