gpt4 book ai didi

c# - 单元测试 Windows.Web.Http HttpClient 与模拟 IHttpFilter 和 IHttpContent,MockedHttpFilter 抛出 System.InvalidCastException

转载 作者:可可西里 更新时间:2023-11-01 08:13:11 24 4
gpt4 key购买 nike

我有一个依赖于 Windows.Web.Http(Windows 10 UAP 应用程序)中的 HttpClient 的类。我想进行单元测试,因此我需要“模拟”HttpClient 来设置 Get-Call 应该返回的内容。我开始使用 HttpClient 使用手写模拟 IHttpFilter 和 IHttpContent 进行“简单”单元测试。它没有按预期工作,我在 Test-Explorer 中收到 InvalidCastException。

单元测试看起来像:

    [TestMethod]
public async Task TestMockedHttpFilter()
{
MockedHttpContent mockedContent = new MockedHttpContent("Content from MockedHttpContent");
MockedHttpFilter mockedHttpFilter = new MockedHttpFilter(HttpStatusCode.Ok, mockedContent);

HttpClient httpClient = new HttpClient(mockedHttpFilter);
var resultContentTask = await httpClient.SendRequestAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("http://dontcare.ch"))).AsTask().ConfigureAwait(false);
// Test stops here, throwing System.InvalidCastException: Specified cast is not valid

// Code not reached...
var result = await resultContentTask.Content.ReadAsStringAsync();
Assert.AreEqual("Content from MockedHttpContent", result);
}

我在 MockedHttpFilter 中实现了 IHttpFilter:

public class MockedHttpFilter : IHttpFilter
{
private HttpStatusCode _statusCode;
private IHttpContent _content;

public MockedHttpFilter(HttpStatusCode statusCode, IHttpContent content)
{
_statusCode = statusCode;
_content = content;
}

public IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request)
{
return AsyncInfo.Run<HttpResponseMessage, HttpProgress>((token, progress) =>
Task.Run<HttpResponseMessage>(()=>
{
HttpResponseMessage response = new HttpResponseMessage(_statusCode);
response.Content = _content;
return response; // Exception thrown after return, but not catched by code/debugger...
}));
}
}

我在 MockedHttpContent 中实现了 IHttpContent:

public class MockedHttpContent : IHttpContent
{
private string _contentToReturn;

public MockedHttpContent(string contentToReturn)
{
_contentToReturn = contentToReturn;
}

public HttpContentHeaderCollection Headers
{
get
{
return new HttpContentHeaderCollection();
}
}

public IAsyncOperationWithProgress<string, ulong> ReadAsStringAsync()
{
return AsyncInfo.Run<string, ulong>((token, progress) => Task.Run<string>(() =>
{
return _contentToReturn;
}));
}
}

Test-Explorer 结果 View 中的错误:

Test Name:  TestMockedHttpFilter
Test FullName: xxx.UnitTests.xxxHttpClientUnitTests.TestMockedHttpFilter
Test Source: xxx.UnitTests\xxxHttpClientUnitTests.cs : line 22
Test Outcome: Failed
Test Duration: 0:00:00.1990313

Result StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at xxx.UnitTests.xxxHttpClientUnitTests.<TestMockedHttpFilter>d__1.MoveNext()
--- 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)
Result Message: Test method xxx.UnitTests.xxxHttpClientUnitTests.TestMockedHttpFilter threw exception:
System.InvalidCastException: Specified cast is not valid.

首先,不确定为什么抛出异常/我做错了什么。也许有人可以为我指出正确的方向或提示下一步要检查/测试什么?

其次,是否有更好的方法来对具有 HttpClient 依赖项(Windows 10 UAP)的代码进行单元测试?

最佳答案

你的单元测试没有意义,你并不是在真正测试你的类,而是你试图测试 HttpClient 类。我将假设一些事情,因为我们没有在您的问题中测试的方法;我假设您执行以下操作:

public async Task<MyCustomClass> MethodUnderTest()
{
// ...

using (var client = new HttpClient(...))
{
// ...

var json = response.Content.ReadAsStringAsync();
return JsonConvert.Deserialize<MyCustomClass>(json);
}
}

如果是这种情况,那么您必须了解您的类不接受某些依赖项。您可以更改类,以便注入(inject)每个外部依赖项,但这可能有点矫枉过正……您真的希望使用和实例化您的类的任何人都必须向您提供 HttpClient 吗?因此,更好的选择是使用可以模拟具体类依赖的模拟框架;大多数模拟框架都可以处理模拟接口(interface)(这些很容易),但很少有框架可以处理模拟具体类。

我建议使用的框架是 Microsoft Fakes框架。 Microsoft Fakes 支持 Shims (Isolation) 和 Stubs (Mocks)。为了控制具体类的成员调用,您需要隔离。

那么,根据我的例子,哪些成员需要被控制?

  1. HttpResponseMessage.Content_Get
  2. HttpContent.ReadAsStringAsync

我认为您不需要改变 JsonConvert.Deserialize<T>() 的行为成员(member),但如果你愿意,你可以。 Microsoft Fakes 框架起初有点让人望而生畏,但是一旦您开始使用它并开始工作,它就会变得更容易使用。或者,您可以使用其他支持隔离的框架:

  • 来自 Telerik 的 JustMock
  • TypeMock 隔离器

也许还有其他的,我不熟悉。

关于c# - 单元测试 Windows.Web.Http HttpClient 与模拟 IHttpFilter 和 IHttpContent,MockedHttpFilter 抛出 System.InvalidCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32843437/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com