在我的Web API应用程序中,我使用HttpServer
在单元测试中包含我的控制器,我正在使用HttpClient
直接调用它,例如:
[Fact]
public void TestMyController()
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
var server = new HttpServer(config);
var client = new HttpClient(server);
var response = client.GetAsync("http://localhost/api/test/values").Result;
}
我注意到(通过逐步调试,并在其他SO帖子上确认),JsonFormatter
并未真正运行 - 它已初始化,但未已行使。由于此测试未打开套接字,并且HttpClient
通过HttpServer
API直接调用HttpMessageHandler
,因此不会运行格式化/序列化,因为它不是需要的。
在我的情况下,我有一些自定义的格式化/序列化/反序列化代码,这些代码在这些测试期间没有被命中,但是当我在真实的Web服务器中运行时,它会受到影响。我想在这些测试中运用该代码;在测试时排除序列化/反序列化代码路径似乎也很危险。对此有何建议?
答案 0 :(得分:1)
下面是一个快速示例,说明如何强制格式化程序进行序列化/反序列化。我们在此处将ObjectContent
转换为StreamContent
。在下面的代码中,对CopyToAsync
的调用触发了格式化程序被强制序列化的路径。如果是去保护,为了确保我们通过格式化,我们希望内容属于ObjectContent
以外的类型,因为ReadAsAsync
具有特殊情况ObjectContnent
的内部逻辑,我们希望规避它。
HttpClient client = new HttpClient(new InMemoryHttpContentSerializationHandler(new HttpServer(config)));
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}