测试使用HttpContext.Current.Request.Files的Web API方法?
我正在尝试编写一个使用HttpContext.Current.Request.Files
的Web API方法的测试,经过详尽的搜索和实验后,我无法弄清楚如何模拟它。 正在测试的方法如下所示:
[HttpPost] public HttpResponseMessage Post() { var requestFiles = HttpContext.Current.Request.Files; var file = requestFiles.Get(0); //do some other stuff... }
我意识到还有其他 类似的 问题 ,但它们没有解决这个具体情况。
如果我试图模拟上下文,我会遇到Http*
对象层次结构的问题。 假设我设置了各种模拟对象(使用Moq ),如下所示:
var mockFiles = new Mock(); mockFiles.Setup(s => s.Count).Returns(1); var mockFile = new Mock(); mockFile.Setup(s => s.InputStream).Returns(new MemoryStream()); mockFiles.Setup(s => s.Get(It.IsAny())).Returns(mockFile.Object); var mockRequest = new Mock(); mockRequest.Setup(s => s.Files).Returns(mockFiles.Object); var mockContext = new Mock(); mockContext.Setup(s => s.Request).Returns(mockRequest.Object);
试图将其分配给当前上下文…
HttpContext.Current = mockContext.Object;
…导致编译器错误/红线,因为它Cannot convert source type 'System.Web.HttpContextBase' to target type 'System.Web.HttpContext'
。
我也尝试钻进构造的控制器对象附带的各种上下文对象,但找不到a)是控制器方法体中HttpContext.Current
调用的返回对象,b)提供对标准HttpRequest
属性的访问,像Files
。
var requestMsg = controller.Request; //returns HttpRequestMessage var context = controller.ControllerContext; //returns HttpControllerContext var requestContext = controller.RequestContext; //read-only returns HttpRequestContext
同样重要的是要注意我无法更改我正在测试的控制器,因此我无法更改构造函数以允许注入上下文。
有没有办法模拟HttpContext.Current.Request.Files
在Web API中进行unit testing?
更新
虽然我不确定这将被团队接受,但我正在尝试更改Post方法以使用Request.Content
,正如Martin Liversage所建议的那样。 它目前看起来像这样:
public async Task Post() { var uploadFileStream = new MultipartFormDataStreamProvider(@"C:\temp"); await Request.Content.ReadAsMultipartAsync(uploadFileStream); //do the stuff to get the file return ActionContext.Request.CreateResponse(HttpStatusCode.OK, "it worked!"); }
我的测试看起来与此类似:
var byteContent = new byte[]{}; var content = new MultipartContent { new ByteArrayContent(byteContent) }; content.Headers.Add("Content-Disposition", "form-data"); var controllerContext = new HttpControllerContext { Request = new HttpRequestMessage { Content = new MultipartContent { new ByteArrayContent(byteContent) } } };
现在我在ReadAsMultipartAsync
上收到错误:
System.IO.IOException: Error writing MIME multipart body part to output stream. ---> System.InvalidOperationException: The stream provider of type 'MultipartFormDataStreamProvider' threw an exception. ---> System.InvalidOperationException: Did not find required 'Content-Disposition' header field in MIME multipart body part.
通过允许您模拟各种上下文对象,构建Web API以支持unit testing。 但是,通过使用HttpContext.Current
您使用的是“旧式” System.Web
代码,该代码使用HttpContext
类,这使得无法对代码进行unit testing。
为了使您的代码可以unit testing,您必须停止使用HttpContext.Current
。 在ASP.NET Web API中发送HTML表单数据:文件上载和多部分MIME,您可以看到如何使用Web API上载文件。 具有讽刺意味的是,此代码还使用HttpContext.Current
来访问MapPath
但在Web API中,您应该使用也在IIS外部工作的HostingEnvironment.MapPath
。 嘲笑后者也存在问题,但是现在我专注于你关于嘲笑请求的问题。
不使用HttpContext.Current
允许您通过分配ControllerContext
属性来对控制器进行unit testing:
var content = new ByteArrayContent( /* bytes in the file */ ); content.Headers.Add("Content-Disposition", "form-data"); var controllerContext = new HttpControllerContext { Request = new HttpRequestMessage { Content = new MultipartContent { content } } }; var controller = new MyController(); controller.ControllerContext = controllerContext;
接受的答案对于OP的问题是完美的。 我想在这里添加我的解决方案,它来自Martin’s,因为这是我在简单搜索如何模拟Web API的Request对象时所指向的页面,因此我可以添加Controller正在寻找的头文件。 我很难找到简单的答案:
var controllerContext = new HttpControllerContext(); controllerContext.Request = new HttpRequestMessage(); controllerContext.Request.Headers.Add("Accept", "application/xml"); MyController controller = new MyController(MockRepository); controller.ControllerContext = controllerContext;
你就是那样; 一种非常简单的方法来创建控制器上下文,您可以使用它“模拟”Request对象并为Controller方法提供正确的标头。
- 访问DelegatingHandler中的ApiController类型
- ASP.NET WebApi IExceptionLogger不捕获exception
- ASP.NET Web API中不允许HTTP PUT
- 在Web API中使用Handler并根据请求解析Unity
- .NET客户端连接到ssl Web API
- Json.Net DeserializeObject失败,只有OData.Delta – 整数
- 如何将Windows身份validation凭据从客户端传递到Web API服务
- 请求/响应记录的响应正文
- WebAPI DataMember通过application / x-www-form-urlencoded进行de / serial化时不使用的名称