unit testing带有伪HTTPContext的ASP.NET Web API控制器

我正在使用以下方法通过ASP.NET Web API控制器上传文件。

[System.Web.Http.HttpPost] public HttpResponseMessage UploadFile() { HttpResponseMessage response; try { int id = 0; int? qId = null; if (int.TryParse(HttpContext.Current.Request.Form["id"], out id)) { qId = id; } var file = HttpContext.Current.Request.Files[0]; int filePursuitId = bl.UploadFile(qId, file); } catch (Exception ex) { } return response; } 

在我的unit testing中,我在调用UploadFile操作之前手动创建了一个HTTPContext类:

 var request = new HttpRequest("", "http://localhost", ""); var context = new HttpContext(request, new HttpResponse(new StringWriter())); HttpContext.Current = context; response = controller.UploadFile(); 

不幸的是,我无法向Form集合添加自定义值,因为它是只读的。 我也无法更改Files集合。

有没有办法在unit testing期间向RequestFormFiles属性添加自定义值以添加所需数据(id和文件内容)?

使用一些像Moq这样的模拟框架。 创建一个模拟HttpRequestBase并使用您需要的任何数据模拟HttpContextBase并在控制器上设置它们。

 using Moq; using NUnit.Framework; using SharpTestsEx; namespace StackOverflowExample.Moq { public class MyController : Controller { public string UploadFile() { return Request.Form["id"]; } } [TestFixture] public class WebApiTests { [Test] public void Should_return_form_data() { //arrange var formData = new NameValueCollection {{"id", "test"}}; var request = new Mock(); request.SetupGet(r => r.Form).Returns(formData); var context = new Mock(); context.SetupGet(c => c.Request).Returns(request.Object); var myController = new MyController(); myController.ControllerContext = new ControllerContext(context.Object, new RouteData(), myController); //act var result = myController.UploadFile(); //assert result.Should().Be.EqualTo(formData["id"]); } } } 

由于您无法控制这些类,因此为什么不包装/抽象一个控件后面的function

 IRequestService request; [HttpPost] public HttpResponseMessage UploadFile() { HttpResponseMessage response; try { int id = 0; int? qId = null; if (int.TryParse(request.GetFormValue("id"), out id)) { qId = id; } var file = request.GetFile(0); int filePursuitId = bl.UploadFile(qId, file); } catch (Exception ex) { //... } return response; } 

其中request是您自定义类型之一的IRequestService

 public interface IRequestService { string GetFormValue(string key); HttpPostedFileBase GetFile(int index); //...other functionality you may need to abstract } 

并且可以像这样实现注入您的控制器

 public class RequestService : IRequestService { public string GetFormValue(string key) { return HttpContext.Current.Request.Form[key]; } public HttpPostedFileBase GetFile(int index) { return new HttpPostedFileWrapper(HttpContext.Current.Request.Files[index]); } } 

在你的unit testing中

 var requestMock = new Mock(); //you then setup the mock to return your fake data //... //and then inject it into your controller var controller = new MyController(requestMock.Object); //Act response = controller.UploadFile();