是否有可单元测试的方法将文件上载到ASP.NET WebAPI?

时间:2012-08-21 23:53:12

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

我正在使用新的ASP.NET WebAPI的项目中工作。我目前的任务是接受上传的文件。到目前为止,我已经使用TDD来驱逐WebAPI代码,但我已经上传了一个墙。我目前正在遵循http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2中的建议,但似乎根本无法将其推出单元测试。为了获取文件和表单数据,我必须使用MultipartFormDataStreamProvider,这是不可能模拟和/或覆盖的。如果没有放弃我的TDD方法,我该怎么办?

以下是示例中的代码:

public Task<HttpResponseMessage> PostFormData()
{
    // Check if the request contains multipart/form-data.
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    string root = HttpContext.Current.Server.MapPath("~/App_Data");
    var provider = new MultipartFormDataStreamProvider(root);

    // Read the form data and return an async task.
    var task = Request.Content.ReadAsMultipartAsync(provider).
        ContinueWith<HttpResponseMessage>(t =>
        {
            if (t.IsFaulted || t.IsCanceled)
            {
                Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
            }

            // This illustrates how to get the file names.
            foreach (MultipartFileData file in provider.FileData)
            {
                Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                Trace.WriteLine("Server file path: " + file.LocalFileName);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        });

    return task;
}

第一个问题是这一行:

var provider = new MultipartFormDataStreamProvider(root);

对于初学者来说,为了对这段代码进行单元测试,我需要能够注入这样的提供者。在那个简单的构造函数调用中,它在“新增它”中排除了太多。还有另一种方式。 (如果没有,WebAPI失败)

4 个答案:

答案 0 :(得分:3)

我抽象出了一个提供程序包装器,所以我可以模拟那些移动部件,比如

    public interface IMultiPartFormDataStreamProviderWrapper : IDependency
    {
        string LocalFileName { get; }
        MultipartFormDataStreamProvider Provider { get; }
    }

    public class MultiPartFormDataStreamProviderWrapper : IMultiPartFormDataStreamProviderWrapper
    {
        public const string UploadPath = "~/Media/Default/Vocabulary/";
        private MultipartFormDataStreamProvider provider;

        public MultiPartFormDataStreamProviderWrapper(IHttpContextAccessor httpContextAccessor)
        {
            provider = new CustomMultipartFormDataStreamProvider(httpContextAccessor.Current().Server.MapPath(UploadPath));
        }

        public string LocalFileName
        {
            get { return provider.FileData[0].LocalFileName; }
        }


        public MultipartFormDataStreamProvider Provider
        {
            get { return provider; }
        }
    }

所以我可以做一些像

这样的事情
    if (Request.Content.IsMimeMultipartContent())
    {
        return Request.Content.ReadAsMultipartAsync(provider.Provider).ContinueWith(t => 
                    {
                        if (t.IsCanceled || t.IsFaulted)
                            return (object)new { success = false };

不理想,但给出了一些想法。你觉得怎么样?

答案 1 :(得分:2)

如果您使用self-hosting功能,则可以编写单元测试:

  • 启动控制器(以及各种其他格式化程序/过滤器/等)
  • 使用HttpClient(或个人,我会使用RestSharp)向该控制器提交文件(使用RestSharp,您可以使用AddFile函数执行此操作)
  • 验证您想要的输入流(例如,通过覆盖提供程序或仅检查传递给测试控制器的值或其他内容)

答案 2 :(得分:2)

如果您还没有在Web API上放弃,您可以尝试System.Net.Http.TestableMultipartStreamProviders,这是Microsoft流提供程序的简单重写。它们的好处是它们依赖SystemWrapper进行文件操作,这意味着可以在单元测试中模拟文件操作。 wiki提供了一些关于利用DI来使测试控制器不那么痛苦的想法。

答案 3 :(得分:-1)

答案是“不”。 ASP.NET是一个基于继承的框架。如果您正在尝试编写基于组合的应用程序,那么您将在某个时刻找到摩擦和路障。是时候切换到Nancy