2010-11-01 72 views
5

我正在使用Moq创建Mock<HttpResponseBase>来测试我为我的MVC2应用程序创建的FileResultHttpResponseBase.Headers在运行测试时为空

FileResultWriteFile(HttpResponseBase response)方法,我有在端部下面的代码:

// Write the final output with specific encoding. 
response.OutputStream.Write(output, 0, output.Length); 
response.AppendHeader("Content-Encoding", encoding); 

它将使用根据从所述请求的首部Accept-Encoding编码utf-8gzip

所以后来在我的测试,我安装我的Mock<HttpResponseBase>像这样:

var mockResponse = new Mock<HttpResponseBase>(); 
mockResponse.Setup(r => r.OutputStream).Returns(new MemoryStream()); 
mockResponse.Setup(r => r.Headers).Returns(new NameValueCollection()); 

但是当我真正检查标题已定,Content-Encoding总是返回null:

var response = mockResponse.Object; 
Assert.AreEqual("utf-8", response.Headers["Content-Encoding"]); 

奇怪的是OutputStream获取写入的数据,我可以断言它正在写入正确的值。

奇怪的是,当我在Web项目中实际调试FileResult时,标头已正确发送。

有没有人有这方面的一些见解?如有必要,我可以提供更多代码。

+0

您可以包含更多关于Moq设置的代码。 – Ahmad 2010-11-01 08:03:41

回答

4

我最终只是嘲讽AppendHeader方法将头强行添加到HttpResponseBase“小号标题:

mockResponse 
    .Setup(r => r.AppendHeader(It.IsAny<string>(), It.IsAny<string>())) 
    .Callback((string k, string v) => mockResponse.Object.Headers.Add(k, v)); 

我怀疑,有一些进一步下跌的AppendHeader里面调用不喜欢的地方加入标题没有实际HttpResponseBase

如果有更好的主意,随时提出建议。希望这有助于未来的人。

2

根据所提供的安装程序代码(不知道它的一个错字),我认为它应该如下

var Response = new Mock<HttpResponseBase>(); 
Response.Setup(r => r.OutputStream).Returns(new MemoryStream()); 
Response.Setup(r => r.Headers).Returns(new NameValueCollection()); 
+0

是的,这是一个错误的帖子。我在文章中的代码中使用了与我使用的实际代码不同的名称。在“真实”代码中,它是我创建的“MockHttpContext”类的一个称为“响应”的属性。上面的代码是修改“Mock ”的* only *部分。 – TheCloudlessSky 2010-11-01 10:07:59

+0

@TheCloudlessSky - 我的答案是渺茫然后 – Ahmad 2010-11-01 10:35:06

+0

这工作。有趣的是你必须使用'MemoryStream'来设置头文件。在此之前尝试了其他一百件事。谢谢,@艾哈迈德。 – Alex 2017-12-29 16:42:08

4

您遇到的问题与您尝试部分模拟HttpResponseBase类的事实有关。写入输出流是可行的,因为属性(在这种情况下为OutputStream)被模拟并从SUT(被测系统)访问。

但是,当你模拟Headers属性时,它只是被嘲弄的属性,而不是AppendHeader,这是你的SUT实际上做的。 Moq创建的默认模拟只是将所有方法和属性存回为默认值,因此AppendHeader实际上并不做任何事情。

有两个解决方案,第一个是纯粹的互动测试,是我的首选方法。不要模拟Headers,而是验证AppendHeader

Mock<HttpResponseBase> responseMock = new Mock<HttpResponseBase>(); 
//the rest of response setup 
FileResult sut = new MyFileResult(); 
sut.WriteFile(responseMock.Object); 
responseMock.Verify(response=>response.AppendHeader("Content-Encoding", "utf8")); 

第二种方法是利用起订量的部分嘲讽,这将使模拟对象调用实际类的方法,除非他们已经建立了明确。

Mock<HttpResponseBase> responseMock = new Mock<HttpResponseBase>(){ CallBase = true }; 
//the rest of response setup 
FileResult sut = new MyFileResult(); 
sut.WriteFile(responseMock.Object); 
Assert.AreEqual("utf-8", responseMock.Object.Headers["Content-Encoding"]); 

当您正在测试与框架的交互时,我倾向于首先使用较小的边距。第二个版本更多的是基于状态的测试,因此理论上你甚至不需要模拟,你可以使用实际的类。然而,在HttpResponseBase的情况下,它的构造函数是受保护的,所以通过创建一个模拟,你基本上是从内联派生出来的,而不必手动编写测试对。

+0

是的,我没有意识到Moq正在扼杀'AppendHeader'。设置'CallBase = true'表明。我喜欢你验证它确实设置了标题的想法,但它确实没有确保标题设置为发送的最终状态(就像你说的那样)。我可能会不小心调用另一个'AppendHeader',然后用另一个调用覆盖它(尽管我想我也可以验证这个)。谢谢你的想法! – TheCloudlessSky 2010-11-01 22:30:29

+0

WriteFile是受保护的成员,你如何直接调用它。 – 2012-09-18 09:16:01

相关问题