Unit test for a method that takes an HttpResponse object as a parameter. OutputStream is unavailable

I am trying to create a unit test for a method that takes an HttpResponse object as a parameter. What is the right way to do this? Hope you experienced testers can help me.

Additional information: I tried to create a fake HttpResponse object by passing to StringWriter.

StringBuilder sb = new StringBuilder(); StringWriter sw = new StringWriter(sb); HttpResponse response = new HttpResponse(sw); RssGenerator.Generate(response, otherParameters); 

Test failed with message: System.Web.HttpException: OutputStream is not available if a custom TextWriter is used. The test method is part of the class library DLL. It uses the Response OutputStream object to create RSSFeed using XMLWriter.

+7
c # unit-testing
source share
6 answers

You must use the System.Web.Abstractions namespace

In particular, take HttpResponseBase ( http://msdn.microsoft.com/en-us/library/system.web.httpresponsebase.aspx ) as an input parameter instead of HttpResponse. You can then mock the HttpResponseBase from your tests. When you have a real HttpResponse to transmit, use HttpResponseWrapper to create an HttpResponseBase.

+12
source

To be truly uniform, you have to make fun of HttpResponse and everything else to check only your method code. I don't know any C # utilities, but this question may help .

Then you can do something like this (like Java with Mockito):

 HttpResponse response = mock(HttpResponse.class); OutputStream outputStream = mock(OutputStream.class); when(response.getOutputStream()).thenReturn(outputStream); RssGenerator.generate(response, otherParameters); 

Of course, you probably need to customize your layout more than that, but you get the general idea.

+3
source

The constructor for HttpResponse not intended for your use, it exists only where the ASP.NET page loop is used, so there is no documentation on how to create it.

You need to configure the HttpResponse object to use the HttpWriter , otherwise it will not allow you to access the underlying stream. However, the constructor set the _httpWriter variable to null , so you need to find another way to set it.

You can use the .NET Reflector program to search the HttpResponse class and see what it does.

+1
source

So the problem with Mocking HttpResponse is that it is sealed, so you cannot extend it (and most mocking frameworks that Mock specific classes simply overwrite virtual methods). Microsoft was also kind enough not to provide interfaces for most of them ... so thanks to MS.

For this reason (in particular), I usually end up writing my own interfaces for all private MS classes, and then writing shell implementators that take the MS class in the constructor and run them in the request as soon as possible. Then you can create mocks interfaces and make them do whatever you like.

+1
source

If you want a more detailed answer, here is what I ended up in my project:

 _mockResponse = new Mock<HttpResponseBase>(); _contentType = string.Empty; _mockResponse.SetupSet(r => r.ContentType = It.IsAny<string>()).Callback<string>(value => _contentType = value); _header = new KeyValuePair<string, string>(); _mockResponse.Setup(r => r.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback((string name, string value) => _header = new KeyValuePair<string, string>(name, value)); _writer = new StringBuilder(); _mockResponse.Setup(r => r.Write(It.IsAny<string>())).Callback<string>(s => _writer.Append(s)); var data = "This is the string to send as response"; UTIL.SendStringAsHttpResponse(data, _mockResponse.Object); Assert.That(_contentType, Is.EqualTo("application/CSV")); Assert.That(_header.Value, Is.EqualTo("attachment; filename=download.csv")); Assert.That(_writer.ToString(), Is.EqualTo(data)); 

where SendStringAsHttpResponse is defined as

 public static void SendStringAsHttpResponse(string data, HttpResponseBase response) 
+1
source

If I could not reorganize the method signature (perhaps this method really only needs one value from HttpResponse?), I would have Eclipse generate a zero implementation of HttpResponse (yes, I am in Java, but this is the idea) - that is, it implements everything methods that return zero - and just fill in only those that I need in the test method, and return some constant values ​​to them. (Yes, I could use some kind of mocking structure.)

The reason you cannot create your own instance of an existing implementation will be very tied to your application server, and you probably need every other nut to even create an instance.

If this turned out to be, I need something more complicated than a simple zero version of HttpResponse, then I would look at NOT testing this method directly: perhaps a test of one or two levels will be simpler and will provide me with the same level of confidence in the code.

0
source

All Articles