【问题标题】:C# Web API Mock HttpContext.Current.Request to test file uploadC# Web API Mock HttpContext.Current.Request 来测试文件上传
【发布时间】:2018-06-28 04:31:20
【问题描述】:

我正在尝试模拟请求以在以下控制器中测试文件上传功能:

public HttpResponseMessage Upload()
{
     var httpRequest = HttpContext.Current.Request;
     if (httpRequest.Files.Count > 0 &&
        httpRequest.Params != null &&
        httpRequest.Params.GetValues("param1") != null &&
        httpRequest.Params.GetValues("param1")[0] != null &&
        httpRequest.Params.GetValues("param2") != null &&
        httpRequest.Params.GetValues("param2")[0] != null)
    {
        var postedFile = httpRequest.Files[0];
        //do something
    }
}

这是我的测试方法

[TestMethod]
public void CheckSuccessfulUpload()
{
    //arrange
    const string fileUploadXML = "<?xml version=\"1.0\" encoding =\"utf8\"?>" +
             "<employees><employee id=\"1\" name=\"A\">" +
             "<employees><employee id=\"2\" name=\"B\">" +
             "<employees><employee id=\"3\" name=\"C\">" +
             "</employees>";

    //Create the file here to upload
    //Set a variable to the My Documents path.
    string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    File.WriteAllText(mydocpath + @"\Employees.xml", fileUploadXML);

    //Mock the Request
    HttpRequest request = new HttpRequest(mydocpath + @"\Employees.xml", "http://localhost/api/DataUpload", "param1=1&param2=2");
    HttpResponse response = new HttpResponse(new StringWriter());
    HttpContext.Current = new HttpContext(request, response);

    //action
    DataUploadController controller = new DataUploadController();
    controller.upload();
    //this is sending the parameters but not the file
}

我能够成功地使用参数而不是文件来命中控制器方法。尝试使用HttpRequestMessageHttpClientMultipartFormDataContent,但它们都不起作用。也无法在网络上获得良好的参考。我也可以使用Mock/Moq 框架。

【问题讨论】:

  • 检查stackoverflow.com/a/38170800/5233410,人们需要停止将他们的代码与System.WebHttpContext 紧密耦合。他们远离它是有原因的。它不是很可测试。
  • 所以我建议您重新考虑该控制器操作的设计,因为 Web api 是最近设计的,并且在 ApiController 中有更多可模拟的入口点。
  • 是的,这将是理想的解决方案。在我完成项目级别更改之前,有没有其他方法可以模拟它并至少在短期内修复它?
  • 不。 HttpContext 和 HttpRequest 是密封的。所以那里没有运气。
  • 使用抽象类HttpContextBase而不是静态HttpContext,然后你就可以模拟它了。

标签: c# unit-testing asp.net-web-api file-upload


【解决方案1】:

编写一个真正测试您的控制器的集成测试怎么样。然后你就可以跳过所有这些嘲弄的东西了。

想象一下你的控制器动作看起来像这样:

[RoutePrefix("api/upload")]
public class UploadController : ApiController
{
    [HttpPost]
    [Route]
    public async Task<IHttpActionResult> Upload()
    {
        var result = await Request.Content.ReadAsMultipartAsync();

        if(result.Contents.Any())
        {
            var postedFile = await result.Contents.First().ReadAsStringAsync();

            // do something

            return Ok("File uploaded successfully");
        }

        return BadRequest("No files uploaded");
    }
}

那么您的集成测试可以如下所示:

[TestMethod]
public async Task CheckSuccessfulUpload()
{
    var baseAddress = new Uri("http://localhost:8000/");
    var config = new HttpSelfHostConfiguration(baseAddress);

    WebApiConfig.Register(config);

    var server = new HttpSelfHostServer(config);
    var client = new HttpClient(server)
    {
        BaseAddress = baseAddress
    };

    const string fileUploadXML = "<?xml version=\"1.0\" encoding =\"utf8\"?>" +
                                    "<employees><employee id=\"1\" name=\"A\">" +
                                    "<employees><employee id=\"2\" name=\"B\">" +
                                    "<employees><employee id=\"3\" name=\"C\">" +
                                    "</employees>";

    var content = new ByteArrayContent(Encoding.UTF8.GetBytes(fileUploadXML));
    content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
    content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    {
        Name = "file",
        FileName = "Employees.xml"
    };

    var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Post, "api/upload")
    {
        Content = new MultipartFormDataContent("----Boundry") { content }
    });

    Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}

希望这能让你继续前进。您可以阅读更多关于自助托管here 的信息。

注意,这里我从我的控制器所在的程序集中引用 WebApiConfig

【讨论】:

  • 我认为这也需要更改我的 UI 以传递文件字节而不是文件?
  • 如果你使用
  • 实际上我在 UI 中使用 ng-fileupload,可能需要更改 UI 代码以传递字节以使这种方法正常工作。让我试试!
猜你喜欢
  • 2015-07-22
  • 1970-01-01
  • 1970-01-01
  • 2019-12-14
  • 2013-09-15
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 2014-10-16
相关资源
最近更新 更多