How to Mock HttpWebRequest when Unit Testing

18 October, 2009 · 2 minutes to read

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:

 

/// <summary>A web request creator for unit testing.</summary> class TestWebRequestCreate : IWebRequestCreate {    static WebRequest nextRequest;    static object lockObject = new object();    static public WebRequest NextRequest    {        get { return nextRequest ;}        set        {            lock (lockObject)            {                nextRequest = value;            }        }    }    /// <summary>See <see cref="IWebRequestCreate.Create"/>.</summary>    public WebRequest Create(Uri uri)    {        return nextRequest;    }    /// <summary>Utility method for creating a TestWebRequest and setting    /// it to be the next WebRequest to use.</summary>    /// <param name="response">The response the TestWebRequest will return.</param>    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; }    /// <summary>Initializes a new instance of <see cref="TestWebRequest"/>    /// with the response to return.</summary>    public TestWebRequest(string response)    {        responseStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(response));    }    /// <summary>Returns the request contents as a string.</summary>    public string ContentAsString()    {        return System.Text.Encoding.UTF8.GetString(requestStream.ToArray());    }    /// <summary>See <see cref="WebRequest.GetRequestStream"/>.</summary>    public override Stream GetRequestStream()    {        return requestStream;    }    /// <summary>See <see cref="WebRequest.GetResponse"/>.</summary>    public override WebResponse GetResponse()    {        return new TestWebReponse(responseStream);    } } class TestWebReponse : WebResponse {    Stream responseStream;    /// <summary>Initializes a new instance of <see cref="TestWebReponse"/>    /// with the response stream to return.</summary>    public TestWebReponse(Stream responseStream)    {        this.responseStream = responseStream;    }    /// <summary>See <see cref="WebResponse.GetResponseStream"/>.</summary>    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 headshot

Written by Richard Willis

Managing Director / Founder

Richard started SalamanderSoft in 2007 after a successful career as a software developer. Wanting to start his own company and with experience in integrating school systems he set out to build the best integration system for schools and to exceed customer expectations. He starting out on his own, doing all the coding, support and sales until finally the growing number of customers meant he needed to start growing the team. He is still heavily involved in coding the core Integration Suite product in addition to running the company and being the first point of contact for prospective customers.

Copyright © 2020 SalamanderSoft Limited