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

2 回答 2

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

}
于 2013-02-26T20:03:38.977 回答
2

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);
}
于 2013-02-26T20:10:42.817 回答