【问题标题】:Creating a mock IHttpFilter for testing Windows.Web.Http.HttpClient创建用于测试 Windows.Web.Http.HttpClient 的模拟 IHttpFilter
【发布时间】:2016-05-23 22:17:41
【问题描述】:

我想创建一个“模拟”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()

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

【问题讨论】:

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


    【解决方案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),这也使代码更易于阅读(免费奖励:))

    第二个答案是,Visual Studio 中有一种叫做“Fakes”的东西,它可以让您能够存根/模拟 HttpClient 和 DateTime 等静态库:

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

    希望这对您有所帮助,并且您更喜欢答案选项 1 :)

    【讨论】:

    • 感谢您的回答和对假货的见解。正如我在链接中所读到的,它们仅在我没有的 VS Enterprise 上可用。我还注意到,在您的回答中,您指的是 System.Net.HttpClient,而我的问题是关于 Windows.Web.Http.HttpClient。创建“模拟”IHttpFilter 实现实际上是微软建议使用此 HttpClient 进行测试的方式。所以我正在寻找 IHttpFilter 实现的答案
    • 在模拟 System.Net.HttpClient 但是你可能会发现thisrichardszalay 的库很有趣
    • 抱歉,我现在看到我在那里回复了错误的东西 - 您想尝试使用 HttpClient 模拟过滤器似乎很奇怪 - 为什么不简单地使用存根?
    • G Dias 我将在应用程序的大部分内容中使用存根。但我还需要更多关于 HttpClient 的“细粒度”测试。
    • 不是Windows.Web.Http.HttpClient的问题,而是System.Net的问题?
    猜你喜欢
    • 2012-10-13
    • 1970-01-01
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多