C# 运行测试时,HttpResponseBase.Header为空
我正在使用Moq创建一个C# 运行测试时,HttpResponseBase.Header为空,c#,asp.net-mvc,unit-testing,moq,C#,Asp.net Mvc,Unit Testing,Moq,我正在使用Moq创建一个Mock来测试我正在为我的MVC2应用程序创建的FileResult 在FileResult的WriteFile(HttpResponseBase response)方法中,我在末尾有以下代码: // Write the final output with specific encoding. response.OutputStream.Write(output, 0, output.Length); response.AppendHeader("Content-Enco
Mock
来测试我正在为我的MVC2应用程序创建的FileResult
在FileResult
的WriteFile(HttpResponseBase response)
方法中,我在末尾有以下代码:
// 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
,如下所示:
var mockResponse = new Mock<HttpResponseBase>();
mockResponse.Setup(r => r.OutputStream).Returns(new MemoryStream());
mockResponse.Setup(r => r.Headers).Returns(new NameValueCollection());
奇怪的是OutputStream得到了写入它的数据,我可以断言它正在写入正确的值
奇怪的是,当我在web项目中调试FileResult
时,头被正确发送
有人对此有所了解吗?如果需要的话,我可以提供更多的代码。根据提供的设置代码(不确定是否输入错误),我认为应该如下所示
var Response = new Mock<HttpResponseBase>();
Response.Setup(r => r.OutputStream).Returns(new MemoryStream());
Response.Setup(r => r.Headers).Returns(new NameValueCollection());
var Response=newmock();
Response.Setup(r=>r.OutputStream).Returns(newmemoryStream());
Response.Setup(r=>r.Headers).Returns(newNameValueCollection());
我最后只是模拟了AppendHeader
方法,将头强制添加到HttpResponseBase
的头中:
mockResponse
.Setup(r => r.AppendHeader(It.IsAny<string>(), It.IsAny<string>()))
.Callback((string k, string v) => mockResponse.Object.Headers.Add(k, v));
mockResponse
.Setup(r=>r.AppendHeader(It.IsAny(),It.IsAny())
.Callback((字符串k,字符串v)=>mockResponse.Object.Headers.Add(k,v));
我怀疑在AppendHeader
的调用中,有一个更深层的东西不喜欢在没有实际HttpResponseBase
的情况下添加头
如果有更好的主意,请随时提出。希望这对将来的人有所帮助。您遇到的问题与您试图部分模拟
HttpResponseBase
类有关。写入输出流是有效的,因为属性(OutputStream
,在本例中)是模拟的,并且是从SUT(测试中的系统)访问的
但是,当您模拟Headers
属性时,只有该属性被模拟,而不是AppendHeader
,这是SUT实际执行的操作。Moq创建的默认mock只是将所有方法和属性存根为返回默认值,因此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 responseMock=new Mock();
//响应设置的其余部分
FileResult sut=新的MyFileResult();
sut.WriteFile(responseMock.Object);
验证(response=>response.AppendHeader(“内容编码”,“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"]);
Mock-responseMock=new-Mock(){CallBase=true};
//响应设置的其余部分
FileResult sut=新的MyFileResult();
sut.WriteFile(responseMock.Object);
Assert.AreEqual(“utf-8”,responseMock.Object.Header[“内容编码”]);
我更喜欢第一个版本,因为您正在测试与框架的交互。第二个版本更多的是基于状态的测试,所以理论上你甚至不需要模拟,你可以使用实际的类。然而,对于
HttpResponseBase
,它的构造函数受到保护,因此几乎是有意义的,因此通过创建模拟,您基本上是从它内联派生的,而不必手动编写双重测试。您可以包含更多关于Moq设置的代码吗?是的,这是文章中的一个错误。我在帖子的代码中对它的命名与我实际使用的代码不同。在“real”代码中,它是我创建的“MockHttpContext”类的一个名为“Response”的属性。上面的代码是唯一修改Mock
@thecloudlessky的部分-我的答案是没有意义的,然后这就成功了。有趣的是,您必须使用MemoryStream
来设置标题。在这之前试过一百种其他的东西。谢谢,@Ahmad.Yeah我没意识到Moq是stubingAppendHeader
。设置CallBase=true
会显示这一点。我喜欢您验证它是否设置了头的想法,但它并不能真正确保头设置为发送的最终状态(如您所说)。我可能会意外地调用另一个AppendHeader
,然后用另一个调用覆盖它(尽管我想我也可以验证这一点)。谢谢你的想法!
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"]);