views:

1013

answers:

5

I am trying to create a unit test for a method that takes a HttpResponse object as a parameter. What the correct way of doing this? I hope you seasoned unit testers out there can help me.

Additional information: I tried creating a fake HttpResponse object by passing in a StringWriter.

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

The test fails with the message: System.Web.HttpException: OutputStream is not available when a custom TextWriter is used. The method being tested is part of a class library dll. It uses the Response object's OutputStream to create an RSSFeed with an XMLWriter.

+2  A: 

To be truly unit, you should mock HttpResponse and everything else to only test your methods code. I don't know of any C# mocking utilities, but this question might help.

You can then do something like this (example is 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 configure your mock more than this, but you get the general idea.

crunchdog
A: 

The constructor for HttpResponse isn't intended for your use, it's only there for the ASP.NET page cycle to use, so there is no documentation on how to create one.

You have to set up the HttpResponse object so that it uses an HttpWriter, otherwise it won't let you access the underlying stream. However, the constructor set the _httpWriter variable to null, so you have to find some other way to set it.

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

Guffa
A: 

If I couldn't refactor the method signature (perhaps the method really only needs one value from the HttpResponse?), I would have Eclipse generate a null implementation of HttpResponse (yes, I'm in Java, but it's the same idea) -- i.e. implements all the methods returning null -- and simply fill in just the ones I need in the method to be tested, and have them return some constant values. (Yeah, could use a mocking framework of some sort, too.)

The reason you can't create your own instance of the existing implementation is it will be heavily tied to your application server, and will likely need all sorts of other gunk to even be instantiated.

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

Rodney Gitzel
A: 

So the problem with Mocking HttpResponse is that it's sealed so you cant extend it (and most mocking frameworks that Mock concrete classes just overwrite virtual methods). Microsoft was also kind enough to not provide interfaces for most of these...so thanks MS.

For this reason (amongst others) I usually end up writing my own Interfaces for all the sealed MS classes and then writing wrapper implementations that take the MS class in the constructor and shunt them in as soon as possible in the request. Then you can create mocks of the interfaces and have them do whatever you like.

ryber
+1  A: 

Need to use namespace System.Web.Abstractions

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

Frank Schwieterman