2013-02-26 79 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