Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Test a file upload, how?

Using MVC3.NET I have a file upload method in a controller that works fine with the following signature public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> file)

How can I unit test this with NUnit? I have looked around and everyone seems to point to Moq but I'm new to unit testing and cannot get Moq working.

I have found interesting blogs such as this: http://danielglyde.blogspot.com/2011/07/tdd-with-aspnet-mvc-3-moq-and.html but am struggling to figure out how the same might be done to 'fake' a file upload, and am also wary that a lot on moq examples that I have managed to find now seem to have deprecated code in them.

I would simply like to know how I can simulate a HttpPostedFileBase so I can test my upload code, using Moq or otherwise - I would be really grateful if someone could give me some code examples on how to do this.

The following code taken from other examples on here:

var file = new Mock<HttpPostedFileBase>();
            file.Setup(f => f.ContentLength).Returns(1);
            file.Setup(f => f.FileName).Returns("test.txt");

controller.upload(file);

generates the following error when I try to compile:

cannot convert from 'Moq.Mock' to 'System.Web.HttpPostedFileBase'

I have changed the method to take a singular HttpPostedFileBase for now, rather than an IEnumerable, as being able to 'mock' one is what I'm trying to focus on for the purpose of this question.

like image 449
DevDave Avatar asked Nov 29 '11 10:11

DevDave


People also ask

How do I create a unit test file?

To get started, select a method, a type, or a namespace in the code editor in the project you want to test, right-click, and then choose Create Unit Tests. The Create Unit Tests dialog opens where you can configure how you want the tests to be created.

What is unit test file?

Unit tests are typically automated tests written and run by software developers to ensure that a section of an application (known as the "unit") meets its design and behaves as intended. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure.


1 Answers

Assuming a standard file upload action:

[HttpPost]
public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> files)
{
    foreach (var file in files)
    {
        var filename = Path.Combine(Server.MapPath("~/app_data"), file.FileName);
        file.SaveAs(filename);
    }
    return View();
}

you could test it like this:

[Test]
public void Upload_Action_Should_Store_Files_In_The_App_Data_Folder()
{
    // arrange
    var httpContextMock = new Mock<HttpContextBase>();
    var serverMock = new Mock<HttpServerUtilityBase>();
    serverMock.Setup(x => x.MapPath("~/app_data")).Returns(@"c:\work\app_data");
    httpContextMock.Setup(x => x.Server).Returns(serverMock.Object);
    var sut = new HomeController();
    sut.ControllerContext = new ControllerContext(httpContextMock.Object, new RouteData(), sut);

    var file1Mock = new Mock<HttpPostedFileBase>();
    file1Mock.Setup(x => x.FileName).Returns("file1.pdf");
    var file2Mock = new Mock<HttpPostedFileBase>();
    file2Mock.Setup(x => x.FileName).Returns("file2.doc");
    var files = new[] { file1Mock.Object, file2Mock.Object };

    // act
    var actual = sut.UploadFile(files);

    // assert
    file1Mock.Verify(x => x.SaveAs(@"c:\work\app_data\file1.pdf"));
    file2Mock.Verify(x => x.SaveAs(@"c:\work\app_data\file2.doc"));
}

Obviously all the HttpContext setup part should be externalized into a reusable class that could be called in the [SetUp] phase of your unit test to prepare the mock context of the subject under test and to avoid repeating it in every single unit test.

like image 68
Darin Dimitrov Avatar answered Oct 06 '22 04:10

Darin Dimitrov