从WebRequest模拟WebResponse

时间:2020-03-05 18:59:55  来源:igfitidea点击:

我终于开始创建一些可以与RESTful Web界面一起使用的应用程序了,但是,我担心每次我按F5来运行一系列测试时,我都会锤打他们的服务器。

基本上,我需要获得一系列Web响应,以便可以测试是否正确解析了各种响应,而不是每次都访问它们的服务器,我认为我可以这样做一次,保存XML,然后在本地工作。

但是,我看不到如何"模拟" WebResponse,因为(AFAIK)它们只能由WebRequest.GetResponse实例化。

你们如何嘲笑这种事情?你?我只是真的不喜欢我要锤击他们的服务器:S我不想过多更改代码,但我希望有一种优雅的方法。

接受后更新

威尔的答案是我需要拍打脸,我知道我错过了一个基本要点!

  • 创建一个接口,该接口将返回代表XML的代理对象。
  • 两次实现接口,一个接口使用WebRequest,另一个接口返回静态"响应"。
  • 然后,接口实现或者根据响应实例化返回类型,或者静态XML。
  • 然后,我们可以在测试或者生产时将所需的类传递给服务层。

敲完代码后,我将粘贴一些示例。

解决方案

回答

你不能最好的办法是将其包装在代理对象中,然后对其进行模拟。或者,我们必须使用一个模拟框架,该框架可以拦截无法模拟的类型,例如TypeMock。但是,我们在谈论的是雄鹿。最好做一点包裹。

显然,我们可以做一些额外的工作。在此处查看投票最高的答案。

回答

这不是一个完美的解决方案,但它以前对我有用,并且为简单起见值得特别注意:

HTTP模拟器

也是typemock论坛中记录的typemock示例:

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);
    }
  }
}

回答

我在寻找做同样的事情时发现了这个问题。在任何地方都找不到答案,但经过进一步挖掘后发现,.Net Framework已内置对此功能的支持。

我们可以使用WebRequest.RegisterPrefix注册工厂对象,当使用该前缀(或者url)时,WebRequest.Create将调用该对象。工厂对象必须实现" IWebRequestCreate",该方法具有一个返回" WebRequest"的单一方法" Create"。在这里,我们可以返回模拟WebRequest

我在上放了一些示例代码
http://blog.salamandersoft.co.uk/index.php/2009/10/how-to-mock-httpwebrequest-when-unit-testing/