开发者

Testing HttpWebRequest/HttpWebResponse client code

We have reasonably complex HTTP client application here. Using TDD proved to be pretty difficult.

We started by using simple interface:

public interface IHttp
{
    TextReader RequestAndOpenTextReader(
        Uri uri, string method, TextReader body = null开发者_StackOverflow);
    WebHeaderCollection RequestAndGetHeaders(
        Uri uri, string method, TextReader body = null);
    void Request(Uri uri, string method, TextReader body = null);
}

However application requires more and more exposure into details of HTTP and continuing to evolve abovementioned interface seems to be a bit redundant.

So goes question. Is there any convenient and standard way to mock out HttpWebRequest/HttpWebResponse without using Profiler API based mocking framework?

Or some alternative open source implementation of client HTTP API?


I wrote a fake for HttpWebRequest, not much implemented in it yet. It has a parameterless constructor so it is easy to use:

        FakeHttpWebRequest fakeHttpWebRequest = new FakeHttpWebRequest();
        Assert.AreEqual("application/x-www-form-urlencoded", fakeHttpWebRequest.ContentType);

/// <summary>
/// http://reflector.webtropy.com/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Net/System/Net/HttpWebRequest@cs/1305376/HttpWebRequest@cs
/// </summary>
public class FakeHttpWebRequest : HttpWebRequest
{
    private static readonly SerializationInfo SerializationInfo;
    private readonly MemoryStream _requestStream;

    static FakeHttpWebRequest()
    {
        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", 500);
        SerializationInfo.AddValue("_ReadWriteTimeout", 500);
        SerializationInfo.AddValue("_MaximumResponseHeadersLength", 128);
        SerializationInfo.AddValue("_ContentLength", 0);
        SerializationInfo.AddValue("_MediaType", 0);
        SerializationInfo.AddValue("_OriginVerb", 0);
        SerializationInfo.AddValue("_ConnectionGroupName", null);
        SerializationInfo.AddValue("_Version", HttpVersion.Version11, typeof(Version));
        SerializationInfo.AddValue("_OriginUri", new Uri("http://test.se"), typeof(Uri));

        serializationInfo.AddValue("_NextExtension", _NextExtension);

    }
    public FakeHttpWebRequest()
        : base(SerializationInfo, new StreamingContext())
    {
        _requestStream = new MemoryStream();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Net.HttpWebRequest"/> class from the specified instances of the <see cref="T:System.Runtime.Serialization.SerializationInfo"/> and <see cref="T:System.Runtime.Serialization.StreamingContext"/> classes.
    /// </summary>
    /// <param name="serializationInfo">A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object that contains the information required to serialize the new <see cref="T:System.Net.HttpWebRequest"/> object. </param><param name="streamingContext">A <see cref="T:System.Runtime.Serialization.StreamingContext"/> object that contains the source and destination of the serialized stream associated with the new <see cref="T:System.Net.HttpWebRequest"/> object. </param>
    protected FakeHttpWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext)
        : base(serializationInfo, streamingContext)
    {
    }

    #region Overrides of HttpWebRequest

    /// <summary>
    /// Gets a <see cref="T:System.IO.Stream"/> object to use to write request data.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.IO.Stream"/> to use to write request data.
    /// </returns>
    /// <exception cref="T:System.Net.ProtocolViolationException">The <see cref="P:System.Net.HttpWebRequest.Method"/> property is GET or HEAD.-or- <see cref="P:System.Net.HttpWebRequest.KeepAlive"/> is true, <see cref="P:System.Net.HttpWebRequest.AllowWriteStreamBuffering"/> is false, <see cref="P:System.Net.HttpWebRequest.ContentLength"/> is -1, <see cref="P:System.Net.HttpWebRequest.SendChunked"/> is false, and <see cref="P:System.Net.HttpWebRequest.Method"/> is POST or PUT. </exception><exception cref="T:System.InvalidOperationException">The <see cref="M:System.Net.HttpWebRequest.GetRequestStream"/> method is called more than once.-or- <see cref="P:System.Net.HttpWebRequest.TransferEncoding"/> is set to a value and <see cref="P:System.Net.HttpWebRequest.SendChunked"/> is false. </exception><exception cref="T:System.NotSupportedException">The request cache validator indicated that the response for this request can be served from the cache; however, requests that write data must not use the cache. This exception can occur if you are using a custom cache validator that is incorrectly implemented. </exception><exception cref="T:System.Net.WebException"><see cref="M:System.Net.HttpWebRequest.Abort"/> was previously called.-or- The time-out period for the request expired.-or- An error occurred while processing the request. </exception><exception cref="T:System.ObjectDisposedException">In a .NET Compact Framework application, a request stream with zero content length was not obtained and closed correctly. For more information about handling zero content length requests, see Network Programming in the .NET Compact Framework.</exception><PermissionSet><IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Net.DnsPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Net.WebPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/></PermissionSet>
    public override Stream GetRequestStream()
    {
        return _requestStream;
    }

    #endregion
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜