Search code examples
c#unit-testingmstestportable-class-library

Async unit testing with portable class libraries


I have a portable class library that needs to target at least .net 4.5 and Silverlight 5. I'm running into an issue trying to write MSTest unit tests in VS 2012 because my library does not use the new async/await paradigm. Is there any way I can test this method?

public static void Get(string uri, string acceptHeader, Action<string> callback)
{
    var request = (HttpWebRequest)WebRequest.Create(uri);
    request.Accept = acceptHeader;        

    request.BeginGetResponse(o =>
    {
        var r = o.AsyncState as HttpWebRequest;
        try
        {
            var response = r.EndGetResponse(o);
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                callback(sr.ReadToEnd());
            }
        }
        catch (Exception ex)
        {
            throw new WebException(string.Format("Unable to access {0}", uri), ex);
        }
    }, request);
}

Solution

  • First, I recommend you reconsider async/await. It's the wave of the future. Microsoft.Bcl.Async provides async support to portable libraries targeting .NET 4.5 and SL5.

    But if you don't want to do that, you can still use async unit tests:

    [TestMethod]
    public async Task Get_RetrievesExpectedString()
    {
      var tcs = new TaskCompletionSource<string>();
      var client = new ... // arrange
    
      client.Get(uri, acceptHeader, result =>
      {
        tcs.SetResult(result);
      });
      var actual = await tcs.Task;
    
      Assert.AreEqual(expected, actual);
    }
    

    Or if you want, you can do it "old-school":

    [TestMethod]
    public void Get_RetrievesExpectedString()
    {
      var mre = new ManualResetEvent(initialState: false);
      string actual = null;
      var client = new ... // arrange
    
      client.Get(uri, acceptHeader, result =>
      {
        actual = result;
        mre.Set();
      });
      mre.WaitOne();
    
      Assert.AreEqual(expected, actual);
    }