2013-12-23 143 views
24

我正在使用以下方法通過ASP.NET Web API控制器上傳文件。單元測試ASP.NET Web API控制器假冒HTTPContext

[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; 
} 

在我的單元測試,我調用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集合。

是否有任何方法可以在單元測試期間向RequestFormFiles屬性添加自定義值以添加所需的數據(標識和文件內容)?

回答

2

改爲使用一些模擬框架,如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<HttpRequestBase>(); 
      request.SetupGet(r => r.Form).Returns(formData); 
      var context = new Mock<HttpContextBase>(); 
      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"]); 
     } 
    } 
} 
+18

謝謝您的答覆。 由於我們使用web.api控制器,我們需要使用HttpControllerContext而不是ControllerContext。 HttpControllerContext不允許在構造函數HttpContextBase中傳遞。 –

+1

只是想知道爲什麼這是高調Pylyp Lebediev說是真實的... – rlee923

1

既然你有過這些類沒有控制權,爲什麼不換行/抽象背後一個功能做控制

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]); 
    } 
} 

在你的單元測試

var requestMock = new Mock<IRequestService>(); 
//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();