首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有没有可能模拟出一个.NET HttpWebResponse?

有没有可能模拟出一个.NET HttpWebResponse?
EN

Stack Overflow用户
提问于 2012-03-22 21:16:10
回答 5查看 48.5K关注 0票数 71

我有一个集成测试,可以从第三方服务器获取一些json结果。它真的很简单,而且效果很好。

我希望停止使用Moq (或任何模拟类库,如ninject等)来劫持并强制返回结果。

这个是可能的吗?

以下是一些示例代码:

代码语言:javascript
复制
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..
}

当然,这个方法是从我的测试中调用的。

我在想,也许我需要传入这个方法(或者类的一个属性?)一个被嘲笑的httpWebResponse或其他东西,但不太确定这是否是正确的方式。此外,响应是httpWebRequest.GetResponse()方法的输出。因此,也许我只需要传递一个模拟的HttpWebRequest

任何带有一些示例代码的建议都将非常受欢迎!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-03-22 21:26:47

您可能希望更改您的消费代码,以便为工厂接收一个接口,该接口创建可以模拟的请求和响应,包装实际的实现。

更新:重新访问

在我的答案被接受之后很长一段时间里,我一直收到负面评价,我承认我最初的答案质量很差,并且做了一个很大的假设。

在4.5+中模拟HttpWebRequest

我最初回答的混乱之处在于,你可以在4.5中模拟HttpWebResponse,但不能在更早的版本中模拟。在4.5中模拟它也使用了过时的构造函数。因此,建议的操作过程是对请求和响应进行抽象。无论如何,下面是一个使用.NET 4.5和Moq 4.2的完整的工作测试。

代码语言:javascript
复制
[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);
}

更好的答案:抽象响应和请求

下面是一个更安全的抽象框架实现,它将在以前的版本中工作(好吧,至少降到3.5 ):

代码语言:javascript
复制
[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();
    }
}
票数 75
EN

Stack Overflow用户

发布于 2012-03-22 21:18:33

而不是模拟HttpWebResponse,而是将调用包装在一个接口后面,并模拟该接口。

如果你正在测试web响应是否命中我想要的站点,这是一个不同的测试,如果A类调用WebResponse接口来获取所需的数据。

对于模拟界面,我更喜欢Rhino mocks。有关如何使用它,请参阅here

票数 5
EN

Stack Overflow用户

发布于 2015-07-07 23:55:31

如果有帮助,请在下面使用NSubstitute代替Moq找到被接受的答案中说明的代码

代码语言:javascript
复制
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);
}

单元测试运行并成功通过。

关于答案的投票我一直在寻找如何有效地做到这一点。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9823039

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档