How to unit test this method in c#?

前端 未结 1 1909
谎友^
谎友^ 2021-02-10 04:21

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          


        
相关标签:
1条回答
  • 2021-02-10 04:47

    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).

    0 讨论(0)
提交回复
热议问题