是否可以模拟 .NET HttpWebResponse? [英] Is it possible to mock out a .NET HttpWebResponse?

查看:29
本文介绍了是否可以模拟 .NET HttpWebResponse?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个集成测试,可以从 3rd 方服务器获取一些 json 结果.这真的很简单,而且效果很好.

i've got an integration test that grabs some json result from a 3rd party server. It's really simple and works great.

我希望停止实际攻击此服务器并使用 Moq(或任何 Mocking 库,如 ninject 等)来劫持并强制返回结果.

I was hoping to stop actually hitting this server and using Moq (or any Mocking library, like ninject, etc) to hijack and force the return result.

这可能吗?

这是一些示例代码:-

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.

我在想,也许我需要传入这个方法(或类的一个属性?)一个模拟的 httpWebResponse 或其他东西,但不太确定这是不是这样.此外,响应是来自 httpWebRequest.GetResponse() 方法的输出..所以也许我只需要传入一个模拟的 HttpWebRequest ?.

I was thinking that maybe I need to pass into this method (or a property of the class?) a mocked httpWebResponse or something but wasn't too sure if this was the way. Also, the response is a output from an httpWebRequest.GetResponse() method .. so maybe I just need to pass in a mocked HttpWebRequest ?.

对一些示例代码的任何建议都非常感谢!

any suggestions with some sample code would be most aprreciated!

推荐答案

您可能希望更改您的消费代码以接收工厂的接口,该工厂创建可以模拟的请求和响应,这些请求和响应包装了实际的实现.

You may wish to change your consuming code to take in an interface for a factory that creates requests and responses that can be mocked which wrap the actual implementation.

>

更新:重温

在我的答案被接受后很长时间内,我的票数一直在下降,我承认我最初的答案质量很差并且做了一个很大的假设.

I've been getting downvotes long after my answer was accepted, and I admit my original answer was poor quality and made a big assumption.

我的原始答案的困惑在于,您可以在 4.5 中模拟 HttpWebResponse,但不能模拟早期版本.在 4.5 中模拟它也使用过时的构造函数.因此,推荐的操作过程是抽象请求和响应.无论如何,下面是使用 .NET 4.5 和 Moq 4.2 的完整工作测试.

The confusion from my original answer lies in the fact that you can mock HttpWebResponse in 4.5, but not earlier versions. Mocking it in 4.5 also utilizes obsolete constructors. So, the recommended course of action is to abstract the request and response. Anyways, below 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);
}

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

这是一个更安全的抽象的基本实现,适用于以前的版本(好吧,至少到 3.5):

Better answer: Abstract the Response and Request

Here's a safer bare-bones implementation of an abstraction that will work for prior versions (well, down to 3.5 at least):

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

这篇关于是否可以模拟 .NET HttpWebResponse?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆