Testing Asynchronous Code

Today I was trying to apply TDD to a piece of code that executes on a separate thread.  The code in question basically creates a new thread and specifies a delegate to be executed on the background thread.

To give you some detail – as part of the login process for the application I’m working on I need to load several external references after authenticating the user.  The problem is that the external system I’m working on is incredibly slow – therefore I need to load these in the background.  I have created an example to illustrate the problem.

public class Loader
{
    private readonly IExternalService service;

    public Loader(IExternalService service)
    {
        this.service = service;
    }

    public void LoadUserExternals(User user)
    {
        ThreadStart loadExternals = delegate
        {
            var externals = new List<External>();
            foreach (var externalReference in user.ExternalReferences)
            {
                externals.Add(service.GetExternal(externalReference));
            }

            user.Externals = externals;
        };
        new Thread(loadExternals).Start();
    }
}

The problem

There is an obvious problem when testing this type of scenario.  We can’t really verify that the externals have been loaded since the test will usually complete before the references have been loaded.  I have seen various clumsy solutions to this problem – the most obvious being the use of Thread.Sleep to wait until the background process completes.

While this would probably work it’s a little fragile and definitely not the most elegant solution to the problem at hand.  A quick Google and a search on StackOverflow gave me quite a few results but no real answers.  (Although this link on Multithreaded Testing and this series on Unit Testing threads came close)

The solution

I basically wanted to allow the code to run synchronously while testing and asynchronously when I’m not.  The solution I came up with was to inject a Thread Factory into the class that would simply execute the code synchronously when testing.  The ThreadFactory would be the default concrete implementation and the MockThreadFactory would be used for testing.

public class ThreadFactory : IThreadFactory
{
    public void StartThread(ThreadStart start)
    {
        new Thread(start).Start();
    }
}
public class MockThreadFactory : IThreadFactory
{
    public void StartThread(ThreadStart start)
    {
        start.Invoke();
    }
}

Now I simply need to use this factory in my code – the line where I create a new thread changes to the following.

threadFactory.StartThread(loadExternals);

Conclusion

Obviously this solution won’t work for everyone – in many cases testing the asynchronous scenario is important.  Regardless, allowing the code to switch from asynchronous to synchronous in this fashion is pretty cool.

Happy coding.