2013-02-26 60 views
1

我有一个可移植的类库,需要至少针对.net 4.5和Silverlight 5.我遇到了一个问题,试图在VS 2012编写MSTest单元测试,因为我的库没有使用新的异步/等待范例。有什么办法可以测试这种方法吗?异步单元测试与便携式类库

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); 
} 

回答

2

首先,我建议你重新考虑async/await。这是未来的潮流。 Microsoft.Bcl.Async为以.NET 4.5和SL5为目标的可移植库提供了支持async

但是,如果你不想做,你仍然可以使用async单元测试:

[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); 
} 

或者,如果你愿意,你可以做“老派”:

[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); 
} 
+0

我实际上打开使用async/await,但* Async方法似乎缺少PCL的'HttpWebRequest'。你会如何改变我的'Get'方法? – user140550 2013-02-26 20:13:53

+0

Task.Factory.FromAsync用于将APM转换为异步/等待。 – Aron 2013-02-26 20:19:19

+0

而在这种转换中,“正确”的方式是让该方法返回我发送回调权限的字符串? – user140550 2013-02-26 20:23:00

2

只是无法抗拒重构代码。你可以在你可以做一天的末尾使用封闭做到以下几点

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

    request.BeginGetResponse(o => 
    { 
     try 
     { 
      var response = request.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); 
     } 
    }, null); 
} 

但是以下

public async static void Get(string uri, string acceptHeader, Action<string> callback) 
{ 
    var request = (HttpWebRequest)WebRequest.Create(uri); 
    request.Accept = acceptHeader;   
    var response = await Task.Factory.FromAsync(
          request.BeginGetRequestStream , 
          request.EndGetRequestStream , 
          uri, 
          null); 
    using (var sr = new StreamReader(response)) 
    { 
     callback(sr.ReadToEnd()); 
    } 
} 

好了,所以这里是我会怎么做

void Main() 
{ 
    {...} 
    var request = (HttpWebRequest)WebRequest.Create(uri); 
    request.Accept = acceptHeader; 
    var response = await request.DownloadStringTaskAwait(); 
    DoSomeStuff(response); 
} 

// Define other methods and classes here 
public static class HttpWebRequestExtension 
{ 
    public async Task<string> DownloadStringTaskAwait(this HttpWebRequest request) 
    { 
     var response = await Task.Factory.FromAsync<Stream>(
          request.BeginGetRequestStream, 
          request.EndGetRequestStream, 
          null); 
        using (var sr = new StreamReader(response)) 
        { 
         return sr.ReadToEnd(); 
        } 
      } 

} 
+0

你的方法编译为PCL? – user140550 2013-02-26 20:06:12

+0

并感谢您的重构。最初的回调是一个单独的方法,因此是cruft。 – user140550 2013-02-26 20:09:26

+1

你应该避免'async void'。在这种情况下,如果下载失败,它会与错误处理混淆。 – 2013-02-26 20:11:46