C#unit testingAPI 2调用

我有一个web api 2 web服务获取方法。 我正在使用HttpContext.Current.Request.UserHostAddress。 当直接调用我的控制器方法时,他没有填充unit testing,因此是null对象的错误。 所以我搜索了如何填写这个并找到以下有助于解决该问题: 为HttpRequestMessage添加IP地址

但是,这需要服务器名称来发送请求。 问题是,当测试运行时,VSExpress将需要为此API Web服务运行,而在运行测试时则不会。 最重要的是,即使它似乎它选择一个随机端口运行,所以我不能像在上面的链接中那样对地址进行硬编码。 鉴于上述问题,我如何测试我的api 2方法?

这是我在测试api方法时爆炸的线

string ip = HttpContext.Current.Request.UserHostAddress; 

[编辑]答案

所以每个人都知道这是代码中的解决方案

 public class MyController : ApiController { private: HttpRequestBase httpRequest; public MyController() { httpRequest = new HttpRequestWrapper(HttpContext.Current.Request) } public MyController(HttpRequestBase http) { httpRequest = http; } public HttpResponseMessage Get() { string ip = httpRequest.UserHostAddress; } } 

我在unit testing中使用Moq:

 Mock httpRequestMock = new Mock(); httpRequestMock.Setup(x => x.UserHostAddress).Returns("127.0.0.1"); // then pass httpRequestMock.Object to my controller ctor and good to go 

通过引用HttpContextBase替换对HttpContext的引用。 在您的代码中,使用HttpContextWrapper实例初始化HttpContextBase ,这是Web堆栈中的默认行为实现。

但是,在您的测试中,请注入一个自定义的HttpContextBase实现,您只需实现测试所需的方法和行为。

如链接中所述:

HttpContextBase类是一个抽象类,包含与HttpContext类相同的成员。 HttpContextBase类使您能够创建类似于HttpContext类的派生类,但您可以自定义并在ASP.NET管道外工作。 执行unit testing时,通常使用派生类来实现具有满足您正在测试的方案的自定义行为的成员。

将控制器与HTTP上下文分离。 可能有一些内置function可以做到这一点,我不熟悉,但一种方法是简单地注入一个可模拟对象。 考虑这样的事情:

 public interface IRequestInformation { string UserHostAddress { get; } } public class RequestInformation : IRequestInformation { public string UserHostAddress { get { return HttpContext.Current.Request.UserHostAddress; } } } 

现在,您已经在接口后面抽象了对HttpContext的依赖。 如果您正在使用依赖项注入,请将该接口注入控制器。 如果你不是,你可以伪造它:

 // in your controller... private IRequestInformation _request; public IRequestInformation RequestInfo { get { if (_request == null) _request = new RequestInformation(); return _request; } set { _request = value; } } 

然后在控制器逻辑中使用它:

 string ip = RequestInfo.UserHostAddress; 

现在在您的unit testing中,您可以提供模拟/假冒等。 对于RequestInfo属性。 手动创建一个或使用模拟库。 如果您手动创建一个,这很简单:

 public class RequestInformationFake : IRequestInformation { public string UserHostAddress { get { return "some known value"; } } } 

然后在安排测试时将其提供给控制器:

 var controller = new YourController(); controller.RequestInformation = new RequestInformationFake(); // run your test