How to Mock HttpWebRequest when Unit Testing

18 October, 2009

How to Mock HttpWebRequest when Unit Testing

One of our latest products interacts with a Restful web service. As this is the core part of its functionality as part of Test Driven Development and Unit Testing I needed to be able to test the calls to the web service using HttpWebRequest.

A quick Google didn’t come up with anything so I started looking at the best way to mock the calls. My initial thought was to extract all use of HttpWebRequest into a separate class, define an interface for setting the request and getting the response and use Dependency Injection to determine whether to use the ‘normal’ class or a mock.

Then I looked a bit closer at WebRequest.Create which is the method you use to create a HttpWebRequest. I noticed that it uses a Factory Method so you could actually register your own factory object depending on the url used. So without any extra code required in the class under test, you can register your factory object and the .Net Framework will automatically use your mocks or stubs. This is pretty cool.

To take advantage of this you need to implement the IWebRequestCreate interface on your factory object, and then register your factory object with WebRequest.RegisterPrefix. What you do in the Create method is up to you, but I created a simple WebRequest and WebResponse pair which store the request for you to test the input, and which returns a configurable response.

First an example of how you can use these:

string response = “my response string here”; WebRequest.RegisterPrefix(“test”, new TestWebRequestCreate()); TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response); string url = “test://MyUrl”; ObjectUnderTest myObject = new ObjectUnderTest(); myObject.Url = url; // DoStuff call the url with a request and then processes the // response as set above myObject.DoStuff(); string requestContent = request.ContentAsString(); Assert.AreEqual(expectedRequestContent, requestContent);

The code for these 3 objects is:

 

///

A web request creator for unit testing.

class TestWebRequestCreate : IWebRequestCreate {    static WebRequest nextRequest;    static object lockObject = new object();    static public WebRequest NextRequest    {        get { return nextRequest ;}        set        {            lock (lockObject)            {                nextRequest = value;            }        }    }    ///

See .

   public WebRequest Create(Uri uri)    {        return nextRequest;    }    ///

Utility method for creating a TestWebRequest and setting    /// it to be the next WebRequest to use.

   /// The response the TestWebRequest will return.    public static TestWebRequest CreateTestRequest(string response)    {        TestWebRequest request = new TestWebRequest(response);        NextRequest = request;        return request;    } } class TestWebRequest : WebRequest {    MemoryStream requestStream = new MemoryStream();    MemoryStream responseStream;    public override string Method { get; set; }    public override string ContentType { get; set; }    public override long ContentLength { get; set; }    ///

Initializes a new instance of    /// with the response to return.

   public TestWebRequest(string response)    {        responseStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(response));    }    ///

Returns the request contents as a string.

   public string ContentAsString()    {        return System.Text.Encoding.UTF8.GetString(requestStream.ToArray());    }    ///

See .

   public override Stream GetRequestStream()    {        return requestStream;    }    ///

See .

   public override WebResponse GetResponse()    {        return new TestWebReponse(responseStream);    } } class TestWebReponse : WebResponse {    Stream responseStream;    ///

Initializes a new instance of    /// with the response stream to return.

   public TestWebReponse(Stream responseStream)    {        this.responseStream = responseStream;    }    ///

See .

   public override Stream GetResponseStream()    {        return responseStream;    } }

 

 

This is quite a simple implementation, just to check the request and return a known response. Once you’ve got this working, you can obviously do more tests such as simulating error conditions.

Richard Willis

Written by

Copyright © 2024 SalamanderSoft Limited