Is it possible to mock .NET's HttpWebResponse?

I have an integration test that captures some json result from a third-party server. It really is simple and works great.

I was hoping to stop actually hitting this server and use Moq (or any Mocking library like ninject, etc.) to capture and force a return.

Is it possible?

Here is a sample code: -

 public Foo GoGetSomeJsonForMePleaseKThxBai() { // prep stuff ... // Now get json please. HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("Http://some.fancypants.site/api/hiThere); httpWebRequest.Method = WebRequestMethods.Http.Get; string responseText; using (var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse()) { using (var streamReader = new StreamReader(httpWebResponse.GetResponseStream())) { json = streamReader.ReadToEnd().ToLowerInvariant(); } } // Check the value of the json... etc.. } 

and, of course, this method is called from my test.

I was thinking that maybe I need to go to this method (or the class property?) To mock httpWebResponse or something like that, but was not too sure if that were the case. In addition, the answer is the result of the httpWebRequest.GetResponse() method .. so maybe I just need to pass in the mocked HttpWebRequest ?.

Any suggestions with some sample code would be most appreciated!

+62
c # unit-testing moq mocking
Mar 22 2018-12-22T00:
source share
7 answers

You might want to modify your consumer code to take an interface for a factory that creates mocking requests and responses that wrap the actual implementation.

Update: Revision

I get downvotes long after my answer has been accepted, and I admit that my original answer was of poor quality and made a big guess.

Mocking HttpWebRequest in 4.5+

The confusion from my original answer is that you can make fun of HttpWebResponse in 4.5, but not in earlier versions. Mocking him in 4.5 also uses legacy constructors. Thus, the recommended course of action is the abstract of the request and response. In any case, the following is a complete working test using .NET 4.5 with Moq 4.2.

 [Test] public void Create_should_create_request_and_respond_with_stream() { // arrange var expected = "response content"; var expectedBytes = Encoding.UTF8.GetBytes(expected); var responseStream = new MemoryStream(); responseStream.Write(expectedBytes, 0, expectedBytes.Length); responseStream.Seek(0, SeekOrigin.Begin); var response = new Mock<HttpWebResponse>(); response.Setup(c => c.GetResponseStream()).Returns(responseStream); var request = new Mock<HttpWebRequest>(); request.Setup(c => c.GetResponse()).Returns(response.Object); var factory = new Mock<IHttpWebRequestFactory>(); factory.Setup(c => c.Create(It.IsAny<string>())) .Returns(request.Object); // act var actualRequest = factory.Object.Create("http://www.google.com"); actualRequest.Method = WebRequestMethods.Http.Get; string actual; using (var httpWebResponse = (HttpWebResponse)actualRequest.GetResponse()) { using (var streamReader = new StreamReader(httpWebResponse.GetResponseStream())) { actual = streamReader.ReadToEnd(); } } // assert actual.Should().Be(expected); } public interface IHttpWebRequestFactory { HttpWebRequest Create(string uri); } 

Best answer: annotation of response and request

Here's a safer implementation of a barebone abstraction that will work for previous versions (well, at least up to 3.5):

 [Test] public void Create_should_create_request_and_respond_with_stream() { // arrange var expected = "response content"; var expectedBytes = Encoding.UTF8.GetBytes(expected); var responseStream = new MemoryStream(); responseStream.Write(expectedBytes, 0, expectedBytes.Length); responseStream.Seek(0, SeekOrigin.Begin); var response = new Mock<IHttpWebResponse>(); response.Setup(c => c.GetResponseStream()).Returns(responseStream); var request = new Mock<IHttpWebRequest>(); request.Setup(c => c.GetResponse()).Returns(response.Object); var factory = new Mock<IHttpWebRequestFactory>(); factory.Setup(c => c.Create(It.IsAny<string>())) .Returns(request.Object); // act var actualRequest = factory.Object.Create("http://www.google.com"); actualRequest.Method = WebRequestMethods.Http.Get; string actual; using (var httpWebResponse = actualRequest.GetResponse()) { using (var streamReader = new StreamReader(httpWebResponse.GetResponseStream())) { actual = streamReader.ReadToEnd(); } } // assert actual.Should().Be(expected); } public interface IHttpWebRequest { // expose the members you need string Method { get; set; } IHttpWebResponse GetResponse(); } public interface IHttpWebResponse : IDisposable { // expose the members you need Stream GetResponseStream(); } public interface IHttpWebRequestFactory { IHttpWebRequest Create(string uri); } // barebones implementation private class HttpWebRequestFactory : IHttpWebRequestFactory { public IHttpWebRequest Create(string uri) { return new WrapHttpWebRequest((HttpWebRequest)WebRequest.Create(uri)); } } public class WrapHttpWebRequest : IHttpWebRequest { private readonly HttpWebRequest _request; public WrapHttpWebRequest(HttpWebRequest request) { _request = request; } public string Method { get { return _request.Method; } set { _request.Method = value; } } public IHttpWebResponse GetResponse() { return new WrapHttpWebResponse((HttpWebResponse)_request.GetResponse()); } } public class WrapHttpWebResponse : IHttpWebResponse { private WebResponse _response; public WrapHttpWebResponse(HttpWebResponse response) { _response = response; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (disposing) { if (_response != null) { ((IDisposable)_response).Dispose(); _response = null; } } } public Stream GetResponseStream() { return _response.GetResponseStream(); } } 
+67
Mar 22 '12 at 13:26
source
+8
Mar 22 2018-12-22T00:
source

Instead of mocking the HttpWebResponse, I would have wrapped a call for an interface and mocked that interface.

If you are testing that the web response has hit the site, I also want this to be a different test than if class A calls the WebResponse interface to get the necessary data.

For mocking the interface, I prefer Rhino mocks . See here for how to use it.

+5
Mar 22 '12 at 13:18
source

If this helps, please find below the code shown in the accepted answer using NSubstitute instead of Moq

 using NSubstitute; /*+ other assemblies*/ [TestMethod] public void Create_should_create_request_and_respond_with_stream() { //Arrange var expected = "response content"; var expectedBytes = Encoding.UTF8.GetBytes(expected); var responseStream = new MemoryStream(); responseStream.Write(expectedBytes, 0, expectedBytes.Length); responseStream.Seek(0, SeekOrigin.Begin); var response = Substitute.For<HttpWebResponse>(); response.GetResponseStream().Returns(responseStream); var request = Substitute.For<HttpWebRequest>(); request.GetResponse().Returns(response); var factory = Substitute.For<IHttpWebRequestFactory>(); factory.Create(Arg.Any<string>()).Returns(request); //Act var actualRequest = factory.Create("http://www.google.com"); actualRequest.Method = WebRequestMethods.Http.Get; string actual; using (var httpWebResponse = (HttpWebResponse)actualRequest.GetResponse()) { using (var streamReader = new StreamReader(httpWebResponse.GetResponseStream())) { actual = streamReader.ReadToEnd(); } } //Assert Assert.AreEqual(expected, actual); } public interface IHttpWebRequestFactory { HttpWebRequest Create(string uri); } 

Unit Test succeeds.

To the vote given in the answer, I was looking for some time how to do this effectively.

+3
Jul 07 '15 at 15:55
source

None of the Microsoft HTTP stack has been designed with unit testing and separation in mind.

You have three options:

  • Make the call on the Internet as small as possible (i.e. send and receive data and transfer to other methods) and check the rest. As for the web call, there should be a lot of magic and very simple.
  • Wrap the HTTP call in another class and pass your object layout during testing.
  • Wrap HttpWebResponse and HttpWebRequest with two other classes. This is what the MVC team did with the HttpContext .

Second option:

 interface IWebCaller { string CallWeb(string address); } 
+2
Mar 22 '12 at 13:21
source

You really can return HttpWebResponse without ridicule, see my answer here . It does not require any "external" proxy interfaces, only the "standard" WebRequest WebResponse and ICreateWebRequest .

If you do not need access to HttpWebResponse and it can only deal with WebResponse , this is even easier; we do this in our unit tests to return β€œoff-the-shelf” responses to content for consumption. I had to β€œgo the extra mile” to return the actual HTTP status codes in order to simulate, for example. 404 responses that require the use of HttpWebResponse so that you can access the StatusCode property, etc.

Other solutions that take everything, HttpWebXXX ignores everything that is supported by WebRequest.Create() , except for HTTP , which can be a handler for any registered prefix that you want to use (via WebRequest.RegisterPrefix() , and if you ignore it, you are missing because it’s a great way to expose other content streams that you otherwise do not have access to, such as Embeeded resource streams, file streams, etc.

In addition, explicitly discarding the return of WebRequest.Create() in HttpWebRequest means a HttpWebRequest path , since the type of the returned WebRequest method again shows some ignorance of how this API actually works.

+1
Jun 04 '12 at 15:35
source

I found a great solution in this post:

It is very easy to use, you just need to do this:

 string response = "my response string here"; WebRequest.RegisterPrefix("test", new TestWebRequestCreate()); TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response); 

And copy these files to your project:

  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; } } 
-one
Apr 07 '15 at 20:26
source



All Articles