The*_*Sky 5 c# asp.net-mvc unit-testing moq
我正在使用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);
Run Code Online (Sandbox Code Playgroud)
它将使用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());
Run Code Online (Sandbox Code Playgroud)
但是当我实际检查标头已设置时,Content-Encoding 总是返回null:
var response = mockResponse.Object;
Assert.AreEqual("utf-8", response.Headers["Content-Encoding"]);
Run Code Online (Sandbox Code Playgroud)
奇怪的是,OutputStream获取写入它的数据,我可以声明它正在写入正确的值.
奇怪的是,当我实际调试FileResultWeb项目时,标头被正确发送.
有没有人对此有所了解?如有必要,我可以提供更多代码.
您遇到的问题与您试图部分模拟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"));
Run Code Online (Sandbox Code Playgroud)
第二种方法是利用 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"]);
Run Code Online (Sandbox Code Playgroud)
我更喜欢第一个版本,因为您正在测试与框架的交互。第二个版本更像是一个基于状态的测试,所以理论上你甚至不需要模拟,你可以使用实际的类。HttpResponseBase然而,在 的情况下,它几乎是有意义的,因为它的构造函数是受保护的,因此通过创建模拟,您基本上是从它内联派生的,而无需手动编写测试替身。
我最终只是模拟了AppendHeader将标头强制添加到 的HttpResponseBase标头中的方法:
mockResponse
.Setup(r => r.AppendHeader(It.IsAny<string>(), It.IsAny<string>()))
.Callback((string k, string v) => mockResponse.Object.Headers.Add(k, v));
Run Code Online (Sandbox Code Playgroud)
我怀疑调用内部还有一些东西AppendHeader不喜欢在没有实际HttpResponseBase到位的情况下添加标头。
如果有更好的想法,欢迎提出。希望这对将来的人有帮助。