我有一个集成测试,可以从第三方服务器获取一些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
?
任何带有一些示例代码的建议都将非常受欢迎!
发布于 2012-03-22 21:26:47
您可能希望更改您的消费代码,以便为工厂接收一个接口,该接口创建可以模拟的请求和响应,包装实际的实现。
更新:重新访问
在我的答案被接受之后很长一段时间里,我一直收到负面评价,我承认我最初的答案质量很差,并且做了一个很大的假设。
在4.5+中模拟HttpWebRequest
我最初回答的混乱之处在于,你可以在4.5中模拟HttpWebResponse
,但不能在更早的版本中模拟。在4.5中模拟它也使用了过时的构造函数。因此,建议的操作过程是对请求和响应进行抽象。无论如何,下面是一个使用.NET 4.5和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 ):
[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();
}
}
发布于 2012-03-22 21:18:33
而不是模拟HttpWebResponse,而是将调用包装在一个接口后面,并模拟该接口。
如果你正在测试web响应是否命中我想要的站点,这是一个不同的测试,如果A类调用WebResponse接口来获取所需的数据。
对于模拟界面,我更喜欢Rhino mocks。有关如何使用它,请参阅here。
发布于 2015-07-07 23:55:31
如果有帮助,请在下面使用NSubstitute代替Moq找到被接受的答案中说明的代码
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);
}
单元测试运行并成功通过。
关于答案的投票我一直在寻找如何有效地做到这一点。
https://stackoverflow.com/questions/9823039
复制相似问题