2009-08-31 28 views
7

我想创建一个将HttpResponse对象作为参数的方法的单元测试。做这件事的正确方法是什么?我希望你能在那里接受测试单元测试人员的帮助。以HttpResponse对象作为参数的方法的单元测试。 OutputStream不可用

附加信息: 我试着通过传入一个StringWriter创建一个假的HttpResponse对象。

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

测试失败并显示消息:System.Web.HttpException:当使用自定义的TextWriter OutputStream的不可用。正在测试的方法是类库dll的一部分。它使用Response对象的OutputStream使用XMLWriter创建一个RSSFeed。

+0

感谢所有好的答案。我会让你知道我最终做了什么。 – 2009-09-02 16:30:45

回答

12

需要使用命名空间System.Web.Abstractions

特别地,采取HttpResponseBase(http://msdn.microsoft.com/en-us/library/system.web.httpresponsebase.aspx)作为输入参数,而不是的HttpResponse。然后你可以从你的测试中嘲笑HttpResponseBase。当你有一个真正的HttpResponse传入时,使用HttpResponseWrapper来产生一个HttpResponseBase。

+3

我花了一段时间才找到这个,所以这里是:HttpResponseWrapper wrapper = new HttpResponseWrapper(this.Response);是如何去做你所描述的。 HttpResponseWrapper扩展HttpResponseBase。 – Aligned 2012-11-13 21:34:40

3

要成为真正的单元,你应该模拟HttpResponse和其他一切,只测试你的方法代码。我不知道任何C#嘲笑实用程序,但这question might help

然后你可以做这样的事情(例如是与Java的Mockito):

HttpResponse response = mock(HttpResponse.class); 
OutputStream outputStream = mock(OutputStream.class); 
when(response.getOutputStream()).thenReturn(outputStream); 

RssGenerator.generate(response, otherParameters); 

当然,你可能需要配置模拟比这更多,但是你得到的总体思路。

1

HttpResponse的构造函数不适合您的使用,它仅适用于ASP.NET页面循环使用,因此没有关于如何创建它的文档。

您必须设置HttpResponse对象,以便它使用HttpWriter,否则它不会让您访问基础流。但是,构造函数将_httpWriter变量设置为null,因此您必须找到其他方法来设置它。

您可以使用.NET Reflector程序在HttpResponse类中挖掘并查看它的功能。

0

如果我不能重构方法签名(也许该方法实际上只需要来自HttpResponse的一个值?),我会让Eclipse生成HttpResponse的一个null实现(是的,我使用Java,但它是同样的想法) - 即实现所有返回null的方法 - 只需填写只需我需要的方法进行测试,并让它们返回一些常量值。 (是的,也可以使用某种类似的嘲讽框架。)

您无法创建自己的现有实现实例的原因是它将与您的应用程序服务器密切相关,并且可能需要各种类型的其他gunk甚至被实例化。

如果事实证明我需要的东西比HttpResponse的一个简单的null版本更复杂,那么我会直接测试这个方法:或许一个或两个测试级别的测试会更简单,并且会为我提供相同的级别对代码的信心。

1

因此,Mocking HttpResponse的问题在于它是封闭的,所以你不能扩展它(和大多数模拟框架,Mock具体类只是覆盖虚拟方法)。微软也非常友善,不为大多数这些提供接口......所以谢谢MS。由于这个原因(除其他外),我通常最终为所有密封的MS类编写我自己的接口,然后编写包含MS类的构造函数中的包装器实现,并尽快将它们分流到请求中。然后,你可以创建接口的模拟,让他们做你喜欢的任何事情。

1

如果你想有一个更详细的答案,这里是我在项目结束后做:

_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)); 

其中SendStringAsHttpResponse被定义为

public static void SendStringAsHttpResponse(string data, HttpResponseBase response) 
相关问题