Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 可以模拟一个.NET HttpWebResponse吗?_C#_.net_Unit Testing_Mocking_Moq - Fatal编程技术网

C# 可以模拟一个.NET HttpWebResponse吗?

C# 可以模拟一个.NET HttpWebResponse吗?,c#,.net,unit-testing,mocking,moq,C#,.net,Unit Testing,Mocking,Moq,我有一个集成测试,从第三方服务器获取一些json结果。这真的很简单,效果很好 我希望停止实际攻击此服务器,并使用Moq(或任何模拟库,如ninject等)劫持并强制返回结果 这可能吗 以下是一些示例代码:- public Foo GoGetSomeJsonForMePleaseKThxBai() { // prep stuff ... // Now get json please. HttpWebRequest httpWebRequest = (HttpWebRequ

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

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

这可能吗

以下是一些示例代码:-

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


任何关于一些示例代码的建议都将是最受欢迎的

我不会模拟HttpWebResponse,而是将调用包装在接口后面,并模拟该接口

如果您正在测试web响应是否也命中了我想要的站点,那么这与class a调用WebResponse接口以获取所需数据不同


用于模拟我更喜欢的界面。请参阅如何使用它。

微软的HTTP协议栈在开发时并没有考虑到单元测试和分离

您有三种选择:

  • 使对web的调用尽可能小(即发送和获取数据,并传递给其他方法),然后测试其余部分。就web调用而言,应该有很多神奇的事情发生,而且非常简单
  • 在另一个类中包装HTTP调用,并在测试时传递模拟对象
  • 用另外两个类包装
    HttpWebResponse
    HttpWebRequest
    。这就是MVC团队使用
    HttpContext
    所做的
第二种选择:

interface IWebCaller
{
    string CallWeb(string address);
}

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

更新:重访 在我的答案被接受很久之后,我就一直遭到反对票,我承认我最初的答案质量很差,并且做了一个很大的假设

在4.5中模拟HttpWebRequest+ 与我最初的答案不同的是,您可以在4.5中模拟
HttpWebResponse
,但不能模拟早期版本。在4.5中模拟它也会使用过时的构造函数。因此,建议的做法是抽象请求和响应。无论如何,下面是一个使用.NET4.5和MOQ4.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);
}
[测试]
public void Create_应_Create_request_和_response_with_stream()
{
//安排
var expected=“响应内容”;
var expectedBytes=Encoding.UTF8.GetBytes(预期);
var responseStream=新内存流();
responseStream.Write(expectedBytes,0,expectedBytes.Length);
responseStream.Seek(0,SeekOrigin.Begin);
var response=newmock();
response.Setup(c=>c.GetResponseStream())。返回(responseStream);
var request=newmock();
request.Setup(c=>c.GetResponse()).Returns(response.Object);
var factory=new Mock();
factory.Setup(c=>c.Create(It.IsAny()))
.Returns(request.Object);
//表演
var actualRequest=factory.Object.Create(“http://www.google.com");
actualRequest.Method=WebRequestMethods.Http.Get;
字符串实际值;
使用(var httpWebResponse=(httpWebResponse)actualRequest.GetResponse())
{
使用(var streamReader=newstreamreader(httpWebResponse.GetResponseStream())
{
实际值=streamReader.ReadToEnd();
}
}
//断言
实际值应为(预期值);
}
公共接口IHttpWebRequestFactory
{
HttpWebRequest创建(字符串uri);
}
更好的回答:抽象出响应和请求 下面是一个更安全的抽象实现,它将适用于以前的版本(至少是3.5版本):

[测试]
public void Create_应_Create_request_和_response_with_stream()
{
//安排
var expected=“响应内容”;
var expectedBytes=Encoding.UTF8.GetBytes(预期);
var responseStream=新内存流();
responseStream.Write(expectedBytes,0,expectedBytes.Length);
responseStream.Seek(0,SeekOrigin.Begin);
var response=newmock();
response.Setup(c=>c.GetResponseStream())。返回(responseStream);
var request=newmock();
request.Setup(c=>c.GetResponse()).Returns(response.Object);
var factory=new Mock();
factory.Setup(c=>c.Create(It.IsAny()))
.Returns(request.Object);
//表演
var actualRequest=factory.Object.Create(“http://www.google.com");
actualRequest.Method=WebRequestMethods.Http.Get;
字符串实际值;
使用(var httpWebResponse=actualRequest.GetResponse())
{
使用(var streamReader=newstreamreader(httpWebResponse.GetResponseStream())
{
实际值=streamReader.ReadToEnd();
}
}
//断言
实际值应为(预期值);
}
公共接口IHttpWebRequest
{
//公开您需要的成员
字符串方法{get;set;}
IHttpWebResponse GetResponse();
}
公共接口IHttpWebResponse:IDisposable
{
//公开您需要的成员
流GetResponseStream();
}
公共接口IHttpWebRequestFactory
{
IHttpWebRequest创建(字符串uri);
}
//基本实现
私有类HttpWebRequestFactory:IHttpWebRequestFactory
{
公共IHttpWebRequest创建(字符串uri)
{
返回新的WrapHttpWebRequest((HttpWebRequest)WebRequest.Create(uri));
}
}
公共类WrapHttpWebRequest:IHttpWebRequest
{
私有只读HttpWebRequest\u请求;
公共WrapHttpWebRequest(HttpWebRequest请求)
{
_请求=请求;
}
公共字符串方法
{
获取{return\u request.Method;}
设置{u request.Method=value;}
}
公共IHttpWebResponse G
[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();
    }
}
string response = "my response string here";
WebRequest.RegisterPrefix("test", new TestWebRequestCreate());
TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response);
    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;
    }
}
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);
}