Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test this method in c#?

i am learning unit testing. How to unit test this method using nunit and rhino mock ?

public ActionResult PrintCSV(Byte[] bytes, string fileName)
{
    var file = File(bytes, "application/vnd.ms-excel");
    var cd = new System.Net.Mime.ContentDisposition()
    {
        CreationDate = DateTime.Now,
        FileName = fileName,
        Inline = false
    };
    Response.AppendHeader("Content-Disposition", cd.ToString());
    return file;
}
like image 427
Ninad More Avatar asked Jan 16 '13 13:01

Ninad More


1 Answers

You will need to mock the HttpContext. Here's an example (it's MSTest but I guess it won't be a hell lot of a pain to port to NUnit - all you need is to rename a couple of attributes):

[TestMethod]
public void PrintCSV_Should_Stream_The_Bytes_Argument_For_Download()
{
    // arrange 
    var sut = new HomeController();
    var bytes = new byte[] { 1, 2, 3 };
    var fileName = "foobar";
    var httpContext = MockRepository.GenerateMock<HttpContextBase>();
    var response = MockRepository.GenerateMock<HttpResponseBase>();
    httpContext.Expect(x => x.Response).Return(response);
    var requestContext = new RequestContext(httpContext, new RouteData());
    sut.ControllerContext = new ControllerContext(requestContext, sut);

    // act
    var actual = sut.PrintCSV(bytes, fileName);

    // assert
    Assert.IsInstanceOfType(actual, typeof(FileContentResult));
    var file = (FileContentResult)actual;
    Assert.AreEqual(bytes, file.FileContents);
    Assert.AreEqual("application/vnd.ms-excel", file.ContentType);
    response.AssertWasCalled(
        x => x.AppendHeader(
            Arg<string>.Is.Equal("Content-Disposition"),
            Arg<string>.Matches(cd => cd.Contains("attachment;") && cd.Contains("filename=" + fileName))
        )
    );
}

As you can see there's a bit of a plumbing code here to setup the test. Personally I use MvcContrib.TestHelper as it simplifies a lot of this plumbing code and makes the test more readable. Check this out:

[TestClass]
public class HomeControllerTests : TestControllerBuilder
{
    private HomeController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        this.sut = new HomeController();
        this.InitializeController(this.sut);
    }

    [TestMethod]
    public void PrintCSV_Should_Stream_The_Bytes_Argument_For_Download()
    {
        // arrange 
        var bytes = new byte[] { 1, 2, 3 };
        var fileName = "foobar";

        // act
        var actual = sut.PrintCSV(bytes, fileName);

        // assert
        var file = actual.AssertResultIs<FileContentResult>();
        Assert.AreEqual(bytes, file.FileContents);
        Assert.AreEqual("application/vnd.ms-excel", file.ContentType);
        this.HttpContext.Response.AssertWasCalled(
            x => x.AppendHeader(
                Arg<string>.Is.Equal("Content-Disposition"),
                Arg<string>.Matches(cd => cd.Contains("attachment;") && cd.Contains("filename=" + fileName))
            )
        );
    }
}

Now the test is much more clear as we can immediately see the initialization phase, the actual invoke of the method under test and the assertion.

Remark: All this being said I don't quite see the point of a controller action that takes a byte array as argument just to stream it back to the client. I mean in order to invoke it the client needs to already have the file, so what's the point? But I guess that was just for illustration purposes. In your actual method the byte array is not passed as argument but is retrieved inside your controller action from some external dependency. In this case you could mock this dependency as well (assuming of course you have properly architected your layers and they are sufficiently weakly coupled).

like image 161
Darin Dimitrov Avatar answered Sep 28 '22 08:09

Darin Dimitrov