使用 属性 字符集的值模拟 HttpWebResponse
Mock HttpWebResponse with value for the property CharacterSet
如何使用 属性 字符集模拟 HttpWebResponse 进行单元测试?在我的代码中,我正在检查 HttpWebResponse.CharacterSet 如下所示。我可以模拟 HttpWebResponse 但在获取 属性 "CharacterSet" 时出现空引用异常。请注意,我无法在模拟中设置 "CharacterSet",因为它是只读且非虚拟的 属性。我正在使用 .Net 4.6.1
public string ReadResponse(HttpWebResponse response)
{
var encoding = (response.CharacterSet == null || response.CharacterSet == "") ? Encoding.UTF8 : Encoding.GetEncoding(response.CharacterSet);
using (var stream = response.GetResponseStream())
{
var reader = new StreamReader(stream, encoding);
var responseString = reader.ReadToEnd();
return responseString;
}
}
我为 HttpWebReponse 编写的模拟是,
public static HttpWebResponse CreateRequestWithResponse(string responseContent)
{
var response = new Mock<HttpWebResponse>(MockBehavior.Loose);
var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent));
response.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK);
response.Setup(c => c.ContentType).Returns("text/xml;charset=\"utf-8\"");
response.Setup(c => c.GetResponseStream()).Returns(responseStream);
var request = new Mock<HttpWebRequest>();
request.Setup(a => a.ContentType).Returns("text/xml;charset=\"utf-8\"");
request.Setup(s => s.GetResponse()).Returns(response.Object);
return response.Object;
}
这是我在获取 "CharacterSet"、
时遇到的错误
我对此做了进一步的研究,看来你不能做你想做的事。问题在于 CharacterSet 属性 使用 headers collection 派生自身。虽然您可以覆盖 Headers 属性,但 CharacterSet 属性 直接查看该字段。 header collection 字段设置为 non-null 值的唯一方法是通过一个内部构造函数,它从一个叫做 cordata 的东西中复制它。
结果是没有安全的方法来模拟 CharacterSet。我想您可以使用反射来找到该字段并以这种方式设置它,但这似乎不是一个好主意,因为实现可能会改变并破坏您的测试。
了解 source code 您可以手动设置 HttpWebResponse
class 的私有属性,这些属性在 CharacterSet
[=21= 的 Get-Handler 中使用]:
public static HttpWebResponse CreateRequestWithResponse(string responseContent)
{
var response = new Mock<HttpWebResponse>(MockBehavior.Loose);
var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent));
response.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK);
response.Setup(c => c.ContentType).Returns("text/xml;charset=\"utf-8\"");
response.Setup(c => c.GetResponseStream()).Returns(responseStream);
HttpWebResponse result = response.Object;
// Set private field behind CharacterSet property
var prop = typeof(HttpWebResponse).GetField("m_CharacterSet", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
prop.SetValue(result, "utf-8");
// Set private field used in CharacterSet getter
prop = typeof(HttpWebResponse).GetField("m_HttpResponseHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
prop.SetValue(result, new WebHeaderCollection());
return result;
}
这取决于内部实现。因此,如果 Microsoft 更改 HttpWebResponse
class 的内部实现,您的测试将被破坏。
如何使用 属性 字符集模拟 HttpWebResponse 进行单元测试?在我的代码中,我正在检查 HttpWebResponse.CharacterSet 如下所示。我可以模拟 HttpWebResponse 但在获取 属性 "CharacterSet" 时出现空引用异常。请注意,我无法在模拟中设置 "CharacterSet",因为它是只读且非虚拟的 属性。我正在使用 .Net 4.6.1
public string ReadResponse(HttpWebResponse response)
{
var encoding = (response.CharacterSet == null || response.CharacterSet == "") ? Encoding.UTF8 : Encoding.GetEncoding(response.CharacterSet);
using (var stream = response.GetResponseStream())
{
var reader = new StreamReader(stream, encoding);
var responseString = reader.ReadToEnd();
return responseString;
}
}
我为 HttpWebReponse 编写的模拟是,
public static HttpWebResponse CreateRequestWithResponse(string responseContent)
{
var response = new Mock<HttpWebResponse>(MockBehavior.Loose);
var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent));
response.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK);
response.Setup(c => c.ContentType).Returns("text/xml;charset=\"utf-8\"");
response.Setup(c => c.GetResponseStream()).Returns(responseStream);
var request = new Mock<HttpWebRequest>();
request.Setup(a => a.ContentType).Returns("text/xml;charset=\"utf-8\"");
request.Setup(s => s.GetResponse()).Returns(response.Object);
return response.Object;
}
这是我在获取 "CharacterSet"、
时遇到的错误我对此做了进一步的研究,看来你不能做你想做的事。问题在于 CharacterSet 属性 使用 headers collection 派生自身。虽然您可以覆盖 Headers 属性,但 CharacterSet 属性 直接查看该字段。 header collection 字段设置为 non-null 值的唯一方法是通过一个内部构造函数,它从一个叫做 cordata 的东西中复制它。
结果是没有安全的方法来模拟 CharacterSet。我想您可以使用反射来找到该字段并以这种方式设置它,但这似乎不是一个好主意,因为实现可能会改变并破坏您的测试。
了解 source code 您可以手动设置 HttpWebResponse
class 的私有属性,这些属性在 CharacterSet
[=21= 的 Get-Handler 中使用]:
public static HttpWebResponse CreateRequestWithResponse(string responseContent)
{
var response = new Mock<HttpWebResponse>(MockBehavior.Loose);
var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(responseContent));
response.Setup(c => c.StatusCode).Returns(HttpStatusCode.OK);
response.Setup(c => c.ContentType).Returns("text/xml;charset=\"utf-8\"");
response.Setup(c => c.GetResponseStream()).Returns(responseStream);
HttpWebResponse result = response.Object;
// Set private field behind CharacterSet property
var prop = typeof(HttpWebResponse).GetField("m_CharacterSet", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
prop.SetValue(result, "utf-8");
// Set private field used in CharacterSet getter
prop = typeof(HttpWebResponse).GetField("m_HttpResponseHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
prop.SetValue(result, new WebHeaderCollection());
return result;
}
这取决于内部实现。因此,如果 Microsoft 更改 HttpWebResponse
class 的内部实现,您的测试将被破坏。