如何对依赖于 HttpWebRequest 和 HttpWebResponse 的现有代码进行单元测试?

How to Unit Test Existing Code that Relies on HttpWebRequest and HttpWebResponse?

提问人:John Saunders 提问时间:1/9/2014 最后编辑:CommunityJohn Saunders 更新时间:6/7/2015 访问量:595

问:

我已经看到了以下问题:

这些对我没有帮助,因为我需要:

  1. 测试直接使用 / 且不带接口的现有代码WebRequestWebResponse
  2. 现有代码依赖于 / ,所以我不能使用自己的派生和类。HttpWebRequestHttpWebResponseWebRequestWebResponse

我知道 ,并且有一个成功的单元测试,证明它有效(一旦你得到正确的前缀)。但该测试只是测试和 .WebRequest.RegisterPrefixWebRequestWebResponse

我尝试了以下方法,但它给出了编译错误(不是警告):

public class MockWebRequest : HttpWebRequest
{
    public MockWebRequest()
    // : base(new SerializationInfo(typeof (HttpWebRequest), new FormatterConverter()), 
    //        new StreamingContext())
    {
    }
}

注释掉两行后,我收到编译错误:

错误 CS0619:“System.Net.HttpWebRequest.HttpWebRequest()”已过时:“此 API 支持 .NET Framework 基础结构,不应在代码中直接使用。

当我取消注释这些行时,我收到 618 警告,但代码在运行时崩溃:

System.Runtime.Serialization.SerializationException: Member '_HttpRequestHeaders' was not found.
   at System.Runtime.Serialization.SerializationInfo.GetElement(String name, Type& foundType)
   at System.Runtime.Serialization.SerializationInfo.GetValue(String name, Type type)
   at System.Net.HttpWebRequest..ctor(SerializationInfo serializationInfo, StreamingContext streamingContext)
   at UnitTests.MockWebRequest..ctor(String responseJson)
   at UnitTests.MockWebRequestCreator.Create(Uri uri)
   at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
   at System.Net.WebRequest.Create(Uri requestUri)
   at code under test

我对如何进行此操作感到茫然(除了默认设置,即只是在这些单元测试上下注,并希望代码在实现时考虑到测试)。

我可能会“肮脏”并做一些令人讨厌的事情,或者类似的事情,但这带来了第三个要求:ISerializable

3.代码必须是可维护的,并且不能比正在测试的代码复杂太多!

OBTW,我不能为此使用 TypeMock,实际上有一点时间限制。该项目几乎已经完成,因此购买的新模拟框架是不可能的。

visual-studio-2012 序列化 net-4.5 webrequest 进行单元测试

评论


答:

0赞 TGH 1/9/2014 #1

在模拟像 httpcontext 这样的单例时,我通常更喜欢使用像 MOQ 这样的模拟框架 asp.net。

还有其他用于模拟的框架,但我发现最小起订量非常灵活和直观

https://github.com/Moq/moq4/wiki/Quickstart

你可以做类似的事情

http://www.syntaxsuccess.com/viewarticle/how-to-mock-httpcontext

另一种方法是通过虚拟方法抽象出对 httpcontext 的调用: 与此技术类似:http://unit-testing.net/CurrentArticle/How-To-Remove-Data-Dependencies-In-Unit-Tests.html

评论

0赞 John Saunders 1/9/2014
不幸的是,没有等价的 for .没有班级。HttpContextBaseHttpWebRequestHttpWebRequestBase
0赞 TGH 1/9/2014
还行。我添加了另一种我有时会使用的方法
1赞 John Saunders 1/9/2014
恐怕这也无济于事。正如我在问题中所说,我无法对所测试的代码进行更改。
0赞 TGH 1/9/2014
好吧,很棘手..我想另一个想法可能是做一个完整的集成测试,你用一个常规的https请求来攻击你的端点(控制器等)。IIS Express 可以在测试中从命令行启动。这可能并不理想,但它至少可以让你断言由所测试代码引起的更改。但是,它不是传统的单元测试
1赞 John Saunders 1/9/2014
我有一个关于委托给真实和.我将继续注册我的前缀,但注册的处理程序将委托给实际类,但会命中类似 .我必须使用它来创建虚拟服务。请注意,这比被测代码更复杂......HttpWebRequestHttpWebResponsetest://localhost/http://localhost/DUMMY_SERVICEHttpListener
0赞 matteagar 10/24/2014 #2

我只是遇到了同样的问题。坦率地说,Microsoft 设置它的方式没有多大意义 - 在 WebRequest.Create 中,它们有一个抽象工厂,但它们既没有提供我们可以实现的 HttpWebRequest 和 HttpWebResponse 接口,也没有提供我们可以用来继承这些类的受保护构造函数。

我提出的解决方案需要对主程序进行一些小的更改,但它可以工作。基本上,我正在做Microsoft应该做的事情。

  1. 创建接口 IHttpWebRequest 和 IHttpWebResponse
  2. 创建实现接口的模拟类
  3. 为实现接口的 HttpWebRequest 和 HttpWebResponse 创建包装器
  4. 将对 WebRequest.Create 的调用替换为我自己的工厂方法,该方法根据需要返回包装器或模拟

根据代码的结构,上述操作的实现可能相对简单,或者可能需要在整个项目中进行更改。就我而言,我们所有的 HTTP 请求都通过一个公共服务,所以情况还不错。

无论如何,对于您的项目来说可能为时已晚,但也许这会对其他人有所帮助。