我认为包装和抽象是最正确的方法。但是,这是我的 hacky 解决方案。
只需使用序列化构造函数重载(它也已过时,但会生成可以抑制的警告)并覆盖您需要更改的方法。
public class FakeHttpWebRequest : HttpWebRequest
{
private static readonly SerializationInfo SerializationInfo = GetSerializationInfo();
private readonly WebResponse response;
public FakeHttpWebRequest(WebResponse response)
#pragma warning disable CS0618 // Type or member is obsolete
: base(
SerializationInfo,
new StreamingContext())
#pragma warning restore CS0618 // Type or member is obsolete
{
this.response = response;
}
public override WebResponse GetResponse()
{
return response;
}
public override Stream GetRequestStream()
{
return new MemoryStream();
}
private static SerializationInfo GetSerializationInfo()
{
// dummy data required for HttpWebRequest() constructor
var serializationInfo = new SerializationInfo(typeof(HttpWebRequest), new FormatterConverter());
serializationInfo.AddValue("_HttpRequestHeaders", new WebHeaderCollection(), typeof(WebHeaderCollection));
serializationInfo.AddValue("_Proxy", null, typeof(IWebProxy));
serializationInfo.AddValue("_KeepAlive", false);
serializationInfo.AddValue("_Pipelined", false);
serializationInfo.AddValue("_AllowAutoRedirect", false);
serializationInfo.AddValue("_AllowWriteStreamBuffering", false);
serializationInfo.AddValue("_HttpWriteMode", 0);
serializationInfo.AddValue("_MaximumAllowedRedirections", 0);
serializationInfo.AddValue("_AutoRedirects", 0);
serializationInfo.AddValue("_Timeout", 0);
serializationInfo.AddValue("_ContentLength", (long)0);
serializationInfo.AddValue("_MediaType", "");
serializationInfo.AddValue("_OriginVerb", "GET");
serializationInfo.AddValue("_ConnectionGroupName", "");
serializationInfo.AddValue("_Version", new Version(1, 0), typeof(Version));
serializationInfo.AddValue("_OriginUri", new Uri("https://fake.uri"), typeof(Uri));
return serializationInfo;
}
}
public class FakeHttpWebResponse : HttpWebResponse
{
private static readonly SerializationInfo SerializationInfo = GetSerializationInfo();
private readonly Stream responseStream;
public FakeHttpWebResponse(HttpStatusCode statusCode, Stream responseStream)
#pragma warning disable CS0618 // Type or member is obsolete
: base(
SerializationInfo,
new StreamingContext())
#pragma warning restore CS0618 // Type or member is obsolete
{
this.StatusCode = statusCode;
this.responseStream = responseStream;
}
public override HttpStatusCode StatusCode { get; }
public override Stream GetResponseStream()
{
return responseStream;
}
private static SerializationInfo GetSerializationInfo()
{
// dummy data required for HttpWebResponse() constructor
var serializationInfo = new SerializationInfo(typeof(HttpWebResponse), new FormatterConverter());
serializationInfo.AddValue("m_HttpResponseHeaders", new WebHeaderCollection(), typeof(WebHeaderCollection));
serializationInfo.AddValue("m_Uri", new Uri("https://fake.uri"), typeof(Uri));
serializationInfo.AddValue("m_Certificate", null, typeof(System.Security.Cryptography.X509Certificates.X509Certificate));
serializationInfo.AddValue("m_Version", new Version(), typeof(Version));
serializationInfo.AddValue("m_StatusCode", (int)HttpStatusCode.HttpVersionNotSupported);
serializationInfo.AddValue("m_ContentLength", (long)0);
serializationInfo.AddValue("m_Verb", "GET");
serializationInfo.AddValue("m_StatusDescription", "");
serializationInfo.AddValue("m_MediaType", "");
return serializationInfo;
}
}
最后,在您的生产代码中提供一种方法来将 WebRequest 创建替换为您的测试代码。
/// <summary>
/// Delegate to create new web request. Can be set to mock actual requests.
/// </summary>
public Func<string, WebRequest> CreateWebRequest { get; set; } = url => WebRequest.Create(url);
并从您的生产代码中使用此委托,而不是直接使用 WebRequest.Create()。
在测试中,您可以将此委托设置为您需要的任何内容。