2013-12-23 26 views
24

次の方法を使用して、ASP.NET Web APIコントローラを介してファイルをアップロードしています。私のユニットテストでユニットテスト偽のHTTPContextを使用した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; 
} 

私は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プロパティにカスタム値を追加して、ユニットテスト中に必要なデータ(IDとファイルの内容)を追加する方法はありますか?

答えて

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コントローラを使用しているので、ControllerContextではなくHttpControllerContextを使用する必要があります。 HttpControllerContextは、コンストラクタHttpContextBaseを渡すことを許可していません。 –

+1

なぜ、これがなぜPylyp Lebedievが言ったときにupvotedされたのか疑問に思う... – rlee923

1

あなたはこれらのクラスを制御することはできませんので、なぜrequestカスタム定義されたタイプのいずれかである場合には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; 
} 

を行う/抽象ラップしない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(); 
関連する問題