运行测试时,HttpResponseBase.Headers为空

我正在使用Moq创建一个Mock来测试我正在为我的MVC2应用程序创建的FileResult

FileResultWriteFile(HttpResponseBase response)方法中,我在最后有以下代码:

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

它将使用utf-8gzip具体取决于请求的Accept-Encoding标头中Accept-Encoding

那么在我的测试中,我设置了我的Mock如下所示:

 var mockResponse = new Mock(); 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时,标头被正确发送。

有没有人对此有所了解? 如有必要,我可以提供更多代码。

我最后只是AppendHeaderAppendHeader方法,强行将标头添加到HttpResponseBase的头文件中:

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

我怀疑在AppendHeader的调用中还有一些东西不喜欢在没有实际的HttpResponseBase情况下添加头文件。

如果有更好的主意,请随时提出建议。 希望这可以帮助将来的某个人。

您遇到的问题与您尝试部分模拟HttpResponseBase类的事实有关。 写入输出流是有效的,因为属性(在本例中为OutputStream )被模拟并从SUT(被测系统)访问。

但是,当您模拟Headers属性时,只有该属性被模拟而不是AppendHeader ,这是您的SUT实际执行的操作。 Moq创建的默认模拟只是将所有方法和属性存根为返回默认值,因此AppendHeader实际上不会执行任何操作。

有两种解决方案,第一种是纯粹的交互测试,是我的首选方法。 不要模拟Headers ,而是validationAppendHeader

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

第二种方法是利用Moq的部分模拟,这将使模拟对象调用实际类的方法,除非它们已被明确设置。

 Mock responseMock = new Mock(){ 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情况下,它的构造函数受到保护几乎是有意义的,因此通过创建一个模拟,你基本上是从内联派生的,而不必手动编写测试double。

基于提供的设置代码(不确定它是否是一个错字),我认为它应该如下所示

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