WebResponse Failure from WebRequest

Finally, I started to mess around with creating some applications that work with RESTful web interfaces, however I am worried that every time I press F5 I clog their servers to run a series of tests.

Basically, I need to get a series of web answers so that I can test. I correctly parse different answers, and not click on their servers every time, I thought that I could do it once, save XML and then work locally.

However, I don’t see how I can “make fun of” WebResponse, since (AFAIK) they can only be created by WebRequest.GetResponse

How do you guys mock this? You? I just don’t like the fact that I clog their servers: S I don’t want to change the code too much, but I expect this to be an elegant way to do this.

Update after Acceptance

The answer will be a blow to the face that I needed, I knew that I was missing a fundamental point!

  • Create an interface that returns a proxy object representing XML.
  • Implement an interface twice that uses WebRequest, another that returns static "responses".
  • The implantable interface then creates an instance of the return type based on the response or static XML.
  • Then you can transfer the required class during testing or in production to the service level.

Once my code has worked, I will insert some samples.

+33
rest xml web-services webrequest
Sep 17 '08 at 20:21
source share
5 answers

I found this question trying to do the same. Could not find the answer anywhere, but after a little more was found that the .NET Framework has support for this.

You can register a factory object with WebRequest.RegisterPrefix , which WebRequest.Create will call when this prefix (or url) is used. The factory object must implement IWebRequestCreate , which has a single Create method that returns WebRequest . Here you can return your WebRequest layout.

I gave an example code http://blog.salamandersoft.co.uk/index.php/2009/10/how-to-mock-httpwebrequest-when-unit-testing/

+59
Oct 18 '09 at 21:50
source share

Here is a solution that does not require ridicule. You implement all three components of WebRequest : IWebRequestCreate WebRequest and WebResponse . See below. My example generates unsuccessful requests (throwing a WebException ), but should be able to adapt it to send "real" responses:

 class WebRequestFailedCreate : IWebRequestCreate { HttpStatusCode status; String statusDescription; public WebRequestFailedCreate(HttpStatusCode hsc, String sd) { status = hsc; statusDescription = sd; } #region IWebRequestCreate Members public WebRequest Create(Uri uri) { return new WebRequestFailed(uri, status, statusDescription); } #endregion } class WebRequestFailed : WebRequest { HttpStatusCode status; String statusDescription; Uri itemUri; public WebRequestFailed(Uri uri, HttpStatusCode status, String statusDescription) { this.itemUri = uri; this.status = status; this.statusDescription = statusDescription; } WebException GetException() { SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new System.Runtime.Serialization.FormatterConverter()); StreamingContext sc = new StreamingContext(); WebHeaderCollection headers = new WebHeaderCollection(); si.AddValue("m_HttpResponseHeaders", headers); si.AddValue("m_Uri", itemUri); si.AddValue("m_Certificate", null); si.AddValue("m_Version", HttpVersion.Version11); si.AddValue("m_StatusCode", status); si.AddValue("m_ContentLength", 0); si.AddValue("m_Verb", "GET"); si.AddValue("m_StatusDescription", statusDescription); si.AddValue("m_MediaType", null); WebResponseFailed wr = new WebResponseFailed(si, sc); Exception inner = new Exception(statusDescription); return new WebException("This request failed", inner, WebExceptionStatus.ProtocolError, wr); } public override WebResponse GetResponse() { throw GetException(); } public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) { Task<WebResponse> f = Task<WebResponse>.Factory.StartNew ( _ => { throw GetException(); }, state ); if (callback != null) f.ContinueWith((res) => callback(f)); return f; } public override WebResponse EndGetResponse(IAsyncResult asyncResult) { return ((Task<WebResponse>)asyncResult).Result; } } class WebResponseFailed : HttpWebResponse { public WebResponseFailed(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext) { } } 

You must create a subclass of HttpWebResponse , because you cannot create it otherwise.

The GetException() part (in the GetException() method) provides values ​​that you cannot override, for example. StatusCode , and this is where our best friend SerializaionInfo comes in! Here you specify values ​​that you cannot override. Obviously, override the parts ( HttpWebResponse ) that you can to go the rest of the way.

How did I get the "names" in all these calls to AddValue() ? From exception messages! It was nice enough to tell me everything in turn, until I made it happy.

Now the compiler will complain about the "obsolete", but it still works, including the .NET Framework version 4.

Here is an example (walkthrough) for reference:

  [TestMethod, ExpectedException(typeof(WebException))] public void WebRequestFailedThrowsWebException() { string TestURIProtocol = TestContext.TestName; var ResourcesBaseURL = TestURIProtocol + "://resources/"; var ContainerBaseURL = ResourcesBaseURL + "container" + "/"; WebRequest.RegisterPrefix(TestURIProtocol, new WebRequestFailedCreate(HttpStatusCode.InternalServerError, "This request failed on purpose.")); WebRequest wr = WebRequest.Create(ContainerBaseURL); try { WebResponse wrsp = wr.GetResponse(); using (wrsp) { Assert.Fail("WebRequest.GetResponse() Should not have succeeded."); } } catch (WebException we) { Assert.IsInstanceOfType(we.Response, typeof(HttpWebResponse)); Assert.AreEqual(HttpStatusCode.InternalServerError, (we.Response as HttpWebResponse).StatusCode, "Status Code failed"); throw we; } } 
+14
Jun 04 2018-12-12T00:
source share

You can not. The best thing to do is to wrap it in a proxy object and then mock it. In addition, you will have to use a framework that can intercept types that cannot be mocked, such as TypeMock. But you are talking about dollars. It is better to make a small package.




Apparently you can with a little extra work. Check the highest voted answer.

+3
17 Sep '08 at 20:31
source share

I found the following blog earlier that explains a pretty good approach using Microsoft Moles.

http://maraboustork.co.uk/index.php/2011/03/mocking-httpwebresponse-with-moles/

In short, the solution suggests the following:

  [TestMethod] [HostType("Moles")] [Description("Tests that the default scraper returns the correct result")] public void Scrape_KnownUrl_ReturnsExpectedValue() { var mockedWebResponse = new MHttpWebResponse(); MHttpWebRequest.AllInstances.GetResponse = (x) => { return mockedWebResponse; }; mockedWebResponse.StatusCodeGet = () => { return HttpStatusCode.OK; }; mockedWebResponse.ResponseUriGet = () => { return new Uri("http://www.google.co.uk/someRedirect.aspx"); }; mockedWebResponse.ContentTypeGet = () => { return "testHttpResponse"; }; var mockedResponse = "<html> \r\n" + " <head></head> \r\n" + " <body> \r\n" + " <h1>Hello World</h1> \r\n" + " </body> \r\n" + "</html>"; var s = new MemoryStream(); var sw = new StreamWriter(s); sw.Write(mockedResponse); sw.Flush(); s.Seek(0, SeekOrigin.Begin); mockedWebResponse.GetResponseStream = () => s; var scraper = new DefaultScraper(); var retVal = scraper.Scrape("http://www.google.co.uk"); Assert.AreEqual(mockedResponse, retVal.Content, "Should have returned the test html response"); Assert.AreEqual("http://www.google.co.uk/someRedirect.aspx", retVal.FinalUrl, "The finalUrl does not correctly represent the redirection that took place."); } 
+2
Mar 17 '11 at 12:51
source share

This is not an ideal solution, but it worked for me before and deserves special care about simplicity:

HTTPSimulator

Also a typemock example registered in the typemock forums :

 using System; using System.IO; using System.Net; using NUnit.Framework; using TypeMock; namespace MockHttpWebRequest { public class LibraryClass { public string GetGoogleHomePage() { HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com"); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using (StreamReader reader = new StreamReader(response.GetResponseStream())) { return reader.ReadToEnd(); } } } [TestFixture] [VerifyMocks] public class UnitTests { private Stream responseStream = null; private const string ExpectedResponseContent = "Content from mocked response."; [SetUp] public void SetUp() { System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] contentAsBytes = encoding.GetBytes(ExpectedResponseContent); this.responseStream = new MemoryStream(); this.responseStream.Write(contentAsBytes, 0, contentAsBytes.Length); this.responseStream.Position = 0; } [TearDown] public void TearDown() { if (responseStream != null) { responseStream.Dispose(); responseStream = null; } } [Test(Description = "Mocks a web request using natural mocks.")] public void NaturalMocks() { HttpWebRequest mockRequest = RecorderManager.CreateMockedObject<HttpWebRequest>(Constructor.Mocked); HttpWebResponse mockResponse = RecorderManager.CreateMockedObject<HttpWebResponse>(Constructor.Mocked); using (RecordExpectations recorder = RecorderManager.StartRecording()) { WebRequest.Create("http://www.google.com"); recorder.CheckArguments(); recorder.Return(mockRequest); mockRequest.GetResponse(); recorder.Return(mockResponse); mockResponse.GetResponseStream(); recorder.Return(this.responseStream); } LibraryClass testObject = new LibraryClass(); string result = testObject.GetGoogleHomePage(); Assert.AreEqual(ExpectedResponseContent, result); } [Test(Description = "Mocks a web request using reflective mocks.")] public void ReflectiveMocks() { Mock<HttpWebRequest> mockRequest = MockManager.Mock<HttpWebRequest>(Constructor.Mocked); MockObject<HttpWebResponse> mockResponse = MockManager.MockObject<HttpWebResponse>(Constructor.Mocked); mockResponse.ExpectAndReturn("GetResponseStream", this.responseStream); mockRequest.ExpectAndReturn("GetResponse", mockResponse.Object); LibraryClass testObject = new LibraryClass(); string result = testObject.GetGoogleHomePage(); Assert.AreEqual(ExpectedResponseContent, result); } } } 
0
Apr 01 '09 at 22:33
source share



All Articles