我正在使用 Moq 创建一个 Mock<HttpResponseBase>
测试 FileResult
我正在为我的 MVC2 应用程序创建。
在WriteFile(HttpResponseBase response)
FileResult
的方法,最后我有以下代码:
// Write the final output with specific encoding.
response.OutputStream.Write(output, 0, output.Length);
response.AppendHeader("Content-Encoding", encoding);
它将使用 utf-8
或 gzip
取决于请求的 Accept-Encoding
的编码标题。
然后在我的测试中,我设置了我的 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
总是返回空值:
var response = mockResponse.Object;
Assert.AreEqual("utf-8", response.Headers["Content-Encoding"]);
奇怪的是 OutputStream 得到了写入它的数据,我可以断言它正在写入正确的值。
奇怪的是,当我实际调试 FileResult
时在 Web 项目中, header 已正确发送。
有没有人对此有所了解?如有必要,我可以提供更多代码。
最佳答案
您遇到的问题与您试图部分模拟 HttpResponseBase
类这一事实有关。写入输出流是可行的,因为该属性(在本例中为 OutputStream
)被模拟并从 SUT(被测系统)访问。
但是,当您模拟 Headers
属性时,只会模拟该属性,而不是 AppendHeader
,这是您的 SUT 实际执行的操作。 Moq 创建的默认模拟只是将所有方法和属性作为返回默认值 stub ,因此 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"));
第二种方法是利用 Moq 的部分模拟,这将使模拟对象调用实际类的方法,除非它们已被显式设置。
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
的情况下,它几乎是有意义的,因为它的构造函数是 protected ,因此通过创建模拟,您基本上是从它内联派生的,而无需手动编写测试替身。
关于c# - 运行测试时 HttpResponseBase.Headers 为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4066184/