18

我正在使用新的 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

4 回答 4

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

不理想,但给人一些印象。你怎么看?

于 2012-10-01T13:38:23.097 回答
3

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

于 2012-11-12T16:41:16.807 回答
1

如果您使用自托管功能,您可以编写一个单元测试:

  • 启动控制器(以及各种其他格式化程序/过滤器/等)
  • 使用 HttpClient (或个人,我会使用RestSharp)将文件提交到该控制器(使用 RestSharp,您可以使用该AddFile函数来执行此操作)
  • 验证您想要的输入流(例如,通过覆盖提供程序或仅检查传递给测试控制器或其他东西的值)
于 2012-08-24T06:58:32.437 回答
-2

答案是不”。ASP.NET 是一个基于继承的框架。如果您尝试编写基于组合的应用程序,您将在某些时候发现摩擦和障碍。是时候切换到像Nancy这样的东西了。

于 2012-09-12T19:21:13.900 回答