.NET核心单元测试如何模拟HttpContext RemoteIpAddress



我有一个使用Identity的.NET Core 3.1项目。对于Login页面处理程序,我添加了一行代码,在用户登录后,它会根据用户的IP地址更新用户位置:

_locationRepository.UpdateUserLocationAsync(HttpContext.Connection.RemoteIpAddress);

完整代码

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_locationRepo.UpdateUserLocation(HttpContext.Connection.RemoteIpAddress);
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}

我的问题是在编写单元测试时,我不知道如何正确地模拟HttpContext。不管我尝试了什么,我总是得到一个空引用异常。

var httpContext = new Mock<HttpContext>();
httpContext.Setup(x => x.Connection.RemoteIpAddress).Returns(new IPAddress(16885952));

如何嘲笑RemoteIpAddress

Xuit+FakeItEay

var mockHttpContextAccessor = new Fake<IHttpContextAccessor>();
var httpContext = new DefaultHttpContext()
{
Connection =
{
RemoteIpAddress = new IPAddress(16885952)
}
};
mockHttpContextAccessor.CallsTo(x => x.HttpContext)
.Returns(httpContext);
var extractedIpAddress = IpExtractor.GetIpAddress(httpContext);
//assert 192.168.1.1

这是我的解决方案

public static void MockIpAddress(this ControllerBase controller) 
{
controller.ControllerContext = new ControllerContext()
{
HttpContext = new DefaultHttpContext()
{
Connection =
{
RemoteIpAddress = new System.Net.IPAddress(16885952)
}
}
};
}

您的设置与任何调用都不匹配。你也需要模拟连接:

var connectionMock = new Mock<Microsoft.AspNetCore.Http.ConnectionInfo>(MockBehavior.Strict);
connectionMock.SetupGet(c => c.RemoteIpAddress).Returns(new IPAddress(16885952));
var httpContext = new Mock<HttpContext>(MockBehavior.Strict);
httpContext.SetupGet(x => x.Connection).Returns(connectionMock.Object);

将MockBehavior设置为Strict,以便在调用未正确设置的属性或方法时引发异常。

最新更新