How to unit test web api controller with Uploader

Hello everybody,

today I want to share piece of code of how to unit test web API2 controller. 

So, recently I had the following task, make web api controller, which accepts posted files, and does something with them. But because at that project I was in role of back end developer ( not full-stack ), it wasn't possible for me to write client side javascript for posting files. What is common way to behave for server side developers? If you proposed to write unit test which will imitate creating and uploading file you are 100% correct. That was my decision as well. 

I don't know how about you, but if it is needed to work with uploaded files, I used to work with HttpContext.Current.Request.Files from which to get access to attached files and do with attachments whatever I want to.

But that not the case with Web Api2 controllers. In order to unit-test controller, other methodology should be used.

Microsoft recomends to use MultipartFormDataStreamProvider class with method ReadAsMultipartAsync .

Here is final code of my web api controller:

var tempFolder = Path.GetTempPath();
var provider = new MultipartFormDataStreamProvider(tempFolder);
// Read the form data.
var tsk = Request.Content.ReadAsMultipartAsync(provider);
tsk.Wait();
var partAsync = tsk.Result;
                
// This illustrates how to get the file names.
foreach (MultipartFileData file in partAsync.FileData)
   {
       var stream = new FileStream(file.LocalFileName, FileMode.Open);
      //persist stream to db
   }
return Request.CreateResponse(HttpStatusCode.OK);

I suppose you may be confused with part 

var tsk = Request.Content.ReadAsMultipartAsync(provider);
tsk.Wait();
var partAsync = tsk.Result;

to be honest, recommended way is little bit another. Like this:

var asyncPart = await Request.Content.ReadAsMultipartAsync(provider);

but for some unknown reason async part ignored all my efforts to force it to do any job, so I was forced to go out of async part and use not absolutely recommended way due to the lack of time.

Then goes unit test part. 

In order to unit test Web Api 2 controller it is required to provide to web api 2 controller HttpControllerContext with some file. In order to have option of creating different files, I created following static method:

public static HttpControllerContext Create(string fileName)
{
    var request = new HttpRequestMessage(HttpMethod.Post, "");
    var content = new MultipartFormDataContent();
    const int lengthStream = 1900;
    var contentString = "some random string";
    var contentBytes = new ByteArrayContent(contentString.StringToByteArray());
 
    contentBytes.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    {
        FileName = fileName
    };
    contentBytes.Headers.Add("Content-Type""text/plain");
    contentBytes.Headers.Add("Content-Length", lengthStream.ToString());
    content.Add(contentBytes);
    request.Content = content;
    
    return new HttpControllerContext(new HttpConfiguration(), new HttpRouteData(new HttpRoute("")), request);
}

After that I was able to write in my unit test following lines of code:

var controllerContext = Create("test.txt");
FileUploadController fc = new FileUploadController();
fc.ControllerContext = controllerContext; fc.AddAttachment("56f3c1bc8ee4f24f8c6bd3bb");

No Comments

Add a Comment