AJ.*_*AJ. 10 c# unit-testing moq httpcontext asp.net-web-api
我正在尝试编写一个Web API方法的测试,该方法使用HttpContext.Current.Request.Files并经过详尽的搜索和实验后,我无法弄清楚如何模拟它.正在测试的方法如下所示:
[HttpPost]
public HttpResponseMessage Post()
{
var requestFiles = HttpContext.Current.Request.Files;
var file = requestFiles.Get(0);
//do some other stuff...
}
Run Code Online (Sandbox Code Playgroud)
如果我试图模拟上下文,我会遇到Http*对象层次结构的问题.假设我设置了各种模拟对象(使用Moq),如下所示:
var mockFiles = new Mock<HttpFileCollectionBase>();
mockFiles.Setup(s => s.Count).Returns(1);
var mockFile = new Mock<HttpPostedFileBase>();
mockFile.Setup(s => s.InputStream).Returns(new MemoryStream());
mockFiles.Setup(s => s.Get(It.IsAny<int>())).Returns(mockFile.Object);
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(s => s.Files).Returns(mockFiles.Object);
var mockContext = new Mock<HttpContextBase>();
mockContext.Setup(s => s.Request).Returns(mockRequest.Object);
Run Code Online (Sandbox Code Playgroud)
试图将其分配给当前上下文...
HttpContext.Current = mockContext.Object;
Run Code Online (Sandbox Code Playgroud)
...导致编译器错误/红线,因为它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
Run Code Online (Sandbox Code Playgroud)
同样重要的是要注意我无法更改我正在测试的控制器,因此我无法更改构造函数以允许注入上下文.
有没有办法模拟HttpContext.Current.Request.FilesWeb API中的单元测试?
更新
虽然我不确定这将被团队接受,但我正在尝试更改Post方法Request.Content,正如Martin Liversage所建议的那样.它目前看起来像这样:
public async Task<HttpResponseMessage> 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!");
}
Run Code Online (Sandbox Code Playgroud)
我的测试看起来与此类似:
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) }
}
};
Run Code Online (Sandbox Code Playgroud)
现在我收到错误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.
Mar*_*age 27
通过允许您模拟各种上下文对象,构建Web API以支持单元测试.但是,通过使用,HttpContext.Current您使用的是"旧式" System.Web代码,该代码HttpContext使得无法对代码进行单元测试.
为了使您的代码可以进行单元测试,您必须停止使用HttpContext.Current.在ASP.NET Web API中发送HTML表单数据:文件上载和多部分MIME,您可以看到如何使用Web API上载文件.具有讽刺意味的是,此代码也用于HttpContext.Current访问MapPath但您应该使用的Web API HostingEnvironment.MapPath也可以在IIS之外使用.嘲笑后者也存在问题但是现在我关注的是关于嘲笑请求的问题.
不使用HttpContext.Current允许您通过分配控制器的ControllerContext属性来对控制器进行单元测试:
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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23623 次 |
| 最近记录: |