如何在 .NET Core 中模拟 HttpContext.GetServerVariable()

问题描述 投票:0回答:3

我正在尝试在.NET Core环境中使用NUnit和Moq测试以下方法:

[HttpGet]
public async Task<IActionResult> DeviceType()
{
    string deviceIp = HttpContext.GetServerVariable("REMOTE_ADDR");
    var result = await DeviceService.GetTypeForAsync(deviceIp);
    return Ok(result);
}

问题是模拟的

HttpContext.GetServerVariable
。我尝试模拟上下文并通过
ControllerContext
:

插入它
var actionContext = new Mock<ActionContext>();
var httpContext = new Mock<HttpContext>();
httpContext.Setup(x => x.GetServerVariable(It.IsAny<string>())).Returns("192.168.1.1");
actionContext.Setup(x => x.HttpContext).Returns(httpContext.Object);
//...
var deviceController = new DeviceController();
deviceController.ControllerContext = new ControllerContext(actionContext.Object);

但是测试未通过并抛出错误:

System.NotSupportedException:不支持的表达式:x => x.GetServerVariable(It.IsAny()) 扩展方法(此处:HttpContextServerVariableExtensions.GetServerVariable)不得在设置/验证表达式中使用。

问题是:如何模拟

HttpContext.GetServerVariable("REMOTE_ADDR")

c# unit-testing asp.net-core moq nunit-3.0
3个回答
2
投票

如错误所示,您无法模拟扩展方法,因为这是静态方法,而不是可重写或可实现的实例或接口方法。

方法位于

HttpContextServerVariableExtensions
中,仅从上下文中获取
IServerVariablesFeature
功能并将调用转发给该实现。

因此,还要模拟

IServerVariablesFeature
及其
this[string]
索引器
,并让该模拟的对象从您模拟的
HttpContext.Features
返回。


0
投票

感谢 @martin-costello 和 @codecaster 的精彩提示,我终于能够模拟它了:

var serverVarsFeature = new Mock<IServerVariablesFeature>();
serverVarsFeature.Setup(x => x["REMOTE_ADDR"]).Returns("192.168.1.1");           
var httpContext = new Mock<HttpContext>();
httpContext.Setup(x => x.Features.Set(serverVarsFeature.Object));
// ...
var deviceController = new DeviceController();
deviceController.ControllerContext = new ControllerContext();
deviceController.ControllerContext.HttpContext = new DefaultHttpContext(httpContext.Object.Features);

0
投票

我得到“对象引用未设置到对象的实例。”使用@1-bug的解决方案时出现异常。 当将它与 @codecaster 的答案和 @martin-costello 的评论结合起来时,我设法得到了一个解决方案,在 HTTP 上下文上调用

GetServerVariable
时返回正确的值。

var mockServerVars = new Mock<IServerVariablesFeature>();
mockServerVars
    .Setup(m => m["REMOTE_ADDR"])
    .Returns("192.168.1.1");
    
var mockFeatures = new Mock<IFeatureCollection>();
mockFeatures
    .Setup(m => m.Get<IServerVariablesFeature>())
    .Returns(mockServerVars.Object);
    
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext
    .SetupGet(m => m.Features)
    .Returns(mockFeatures.Object);

与@1_bug的解决方案相比,差异是

  1. 我添加了创建模拟
    IFeatureCollection
    的中间步骤,它返回服务器变量功能。
  2. 在设置上下文时,我没有调用
    x.Features.Set
    ,而是用我的模拟功能集合替换整个
    x.Features

当在 HTTP 上下文中调用

GetServerVariable
时,它将尝试从
IServerVariablesFeature
属性(即从我模拟的功能集合中)获取
HttpContext.Features
。发现这样的功能存在(不为空),
GetServerVariable
将使用模拟的服务器变量功能来获取IP地址。

© www.soinside.com 2019 - 2024. All rights reserved.