创建一个模拟IHttpFilter来测试Windows.Web.Http.HttpClient

时间:2016-02-12 16:55:32

标签: c# unit-testing windows-runtime mocking tdd

我想创建一个“模拟”IHttpFilter实现来测试Windows.Web.Http HttpClient的调用。这是我在实现中的SendRequestAsync方法

 public IAsyncOperationWithProgress<HttpResponseMessage,HttpProgress> 
    SendRequestAsync(HttpRequestMessage request)
            {
                HttpResponseMessage response = new HttpResponseMessage(_statusCode);
                response.Content = _content;

                //This is the problematic part
                return AsyncInfo.Run<HttpResponseMessage, HttpProgress>(
                    (token, progress) => Task.Run<HttpResponseMessage>(
                        () => { return response; }));           
            }

在我的测试方法中,我像这样使用它。这也是在应用程序中使用HttpClient的方式。

//This Throws an InvalidCastException
var result = await client.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.nomatter.com")));

但它会抛出InvalidCastException

Result Message: Test method UnitTestLibrary1.UnitTest.TestHttp threw exception: 
System.InvalidCastException: Specified cast is not valid.
Result StackTrace:  
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at UnitTestLibrary1.UnitTest.<TestHttp>d__0.MoveNext() in c:\Users\****\UniversalPCLUnitTest\UnitTestLibrary1\UnitTest1.cs:line 40
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

我无法找出抛出异常的原因。有人遇到过同样的问题吗?

1 个答案:

答案 0 :(得分:-1)

这个问题有两个答案。

第一个答案是你甚至不应该尝试模拟System.Net.HttpClient。这个类应该在你的应用程序中实例化,可能是一个单身人士。

你通常会将HttpClient的使用包装成某种合同,IE

public interface ICanGetHttpBodies{
    string AsString(Uri uri);
}

然后当然,使用该合同,并在需要时模拟出来:

[TestMethod, ExpectedException(typeof(ProgramException))]
public void MyMethod_WhenEmptyBody_ThrowsException()
{
    // Arrange 
    var emptyBody = "";
    var getBodyMock = new Mock<ICanGetHttpBodies>()
        .Setup(m => m.AsString(It.IsAny<Uri>())
        .Returns(emptyBody);

    // Act & Assert
}

通过这种方式,您可以完全控制代码流,您已将HttpClient隐藏在契约中,该契约为您提供了意义(ICanGetHttpBodies),使代码更易于阅读(免费奖励:))

第二个答案是,有一种叫做'#34; Fakes&#34;在Visual Studio中,可以使您能够存根/模拟静态库,如HttpClient和DateTime:

https://msdn.microsoft.com/en-us/library/hh549175.aspx

希望这有任何帮助,并且您更喜欢回答选项1:)