我有一个集成测试,从第三方服务器抓取一些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
?。
任何建议与一些样本代码将是最赞赏!
7条答案
按热度按时间wvyml7n51#
您可能希望更改您的消费代码,以便为工厂引入一个接口,该工厂创建可以被模拟的请求和响应,这些请求和响应 Package 了实际的实现。
更新:重新访问
在我的答案被接受很久之后,我一直在获得反对票,我承认我最初的答案质量很差,而且做了一个很大的假设。
在4.5+中模拟HttpWeb请求
我最初的回答中的困惑在于,你可以在4.5中模拟
HttpWebResponse
,但不能在更早的版本中模拟。在4.5中模拟它还使用了过时的构造函数。因此,推荐的操作过程是抽象请求和响应。无论如何,下面是一个完整的工作测试,使用.NET 4.5和Moq 4.2。更好的答案:摘要响应和请求
下面是一个更安全的抽象的基本实现,它适用于以前的版本(好吧,至少到3.5):
2ekbmq322#
我不会模仿HttpWebResponse,而是将调用 Package 在一个接口后面,并模仿该接口。
如果您正在测试Web响应是否命中了我也想要的站点,这与类A是否调用WebResponse接口以获取所需数据是不同的测试。
对于模拟接口,我更喜欢Rhino mocks。关于如何使用它,请参见here。
b1payxdu3#
Microsoft的HTTP堆栈在开发时没有考虑到单元测试和分离。
您有三个选项:
HttpWebResponse
和HttpWebRequest
,这就是MVC团队对HttpContext
所做的。第二种选择:
aiazj4mn4#
如果有帮助,请在下面找到使用NSubstitute代替Moq的已接受答案中的代码
单元测试运行并成功通过。
我一直在寻找一段时间如何有效地做到这一点的答案。
093gszye5#
实际上,你可以返回
HttpWebResponse
而不需要模仿,请看我的回答,它不需要任何“外部”代理接口,只需要“标准”的WebRequest
WebResponse
和ICreateWebRequest
。如果您不需要访问
HttpWebResponse
,而只需要处理WebResponse
,那就更容易了;我们在单元测试中这样做是为了返回“预制的”内容响应以供使用。为了返回实际的HTTP状态代码,我不得不“走额外的路”,以模拟例如404个响应,这需要您使用HttpWebResponse
,以便您可以访问StatusCode
属性等。其他解决方案假设所有内容都是
HttpWebXXX
,忽略了WebRequest.Create()
支持的所有内容,除了HTTP,HTTP可以是您想要使用的任何注册前缀的处理程序(通过WebRequest.RegisterPrefix()
,如果您忽略了这一点,您就错过了,因为这是一种很好的方式来公开您无法访问的其他内容流,例如嵌入式资源流、文件流、等等。此外,显式地将
WebRequest.Create()
的返回强制转换为HttpWebRequest
是到breakage的路径**,因为方法的返回类型是WebRequest
,这再次表明对API实际工作方式的一些无知。sbdsn5lh6#
虽然有一个公认的答案,我想分享我的观点。有很多时候,修改源代码是不是一个选项的建议。此外,答案引入了至少可以说很多生产代码。
因此,我更喜欢使用免费的harmonyLib,并通过拦截
WebRequest.Create
静态方法来修补CLR,而不对生产代码进行任何更改。我的修改版本如下所示:
rkkpypqq7#
我在这个blog post中找到了一个很好的解决方案:
它非常容易使用,你只需要这样做:
并将这些文件复制到您的项目: