gpt4 book ai didi

c# - 如何对 HttpContext.SignInAsync() 进行单元测试?

转载 作者:可可西里 更新时间:2023-11-01 08:38:03 27 4
gpt4 key购买 nike

SignInAsync() Source Code

我在单元测试中遇到了一些问题。

  1. DefaultHttpContext.RequestServicesnull
  2. 我试图创建AuthenticationService 对象,但我不知道要传递什么参数

我该怎么办?如何对 HttpContext.SignInAsync() 进行单元测试?

待测方法

public async Task<IActionResult> Login(LoginViewModel vm, [FromQuery]string returnUrl)
{
if (ModelState.IsValid)
{
var user = await context.Users.FirstOrDefaultAsync(u => u.UserName == vm.UserName && u.Password == vm.Password);
if (user != null)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.UserName)
};
var identity = new ClaimsIdentity(claims, "HappyDog");

// here
await HttpContext.SignInAsync(new ClaimsPrincipal(identity));
return Redirect(returnUrl ?? Url.Action("Index", "Goods"));
}
}
return View(vm);
}

到目前为止我尝试了什么。

[TestMethod]
public async Task LoginTest()
{
using (var context = new HappyDogContext(_happyDogOptions))
{
await context.Users.AddAsync(new User { Id = 1, UserName = "test", Password = "password", FacePicture = "FacePicture" });
await context.SaveChangesAsync();

var controller = new UserController(svc, null)
{
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
// How mock RequestServices?
// RequestServices = new AuthenticationService()?
}
}
};
var vm = new LoginViewModel { UserName = "test", Password = "password" };
var result = await controller.Login(vm, null) as RedirectResult;
Assert.AreEqual("/Goods", result.Url);
}
}

最佳答案

HttpContext.SignInAsync 是使用RequestServices 的扩展方法,即IServiceProvider。那是你必须 mock 的。

context.RequestServices
.GetRequiredService<IAuthenticationService>()
.SignInAsync(context, scheme, principal, properties);

您可以通过创建派生自所用接口(interface)的类来手动创建伪造/模拟,也可以使用类似 Moq 的模拟框架。

//...code removed for brevity

var authServiceMock = new Mock<IAuthenticationService>();
authServiceMock
.Setup(_ => _.SignInAsync(It.IsAny<HttpContext>(), It.IsAny<string>(), It.IsAny<ClaimsPrincipal>(), It.IsAny<AuthenticationProperties>()))
.Returns(Task.FromResult((object)null));

var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock
.Setup(_ => _.GetService(typeof(IAuthenticationService)))
.Returns(authServiceMock.Object);

var controller = new UserController(svc, null) {
ControllerContext = new ControllerContext {
HttpContext = new DefaultHttpContext {
// How mock RequestServices?
RequestServices = serviceProviderMock.Object
}
}
};

//...code removed for brevity

您可以在他们的 Quick start 上阅读有关如何使用 Moq 的信息

您可以像模拟其他依赖项一样轻松地模拟 HttpContext,但是如果存在不会导致不良行为的默认实现,那么使用它可以使事情的安排变得更加简单

例如,一个实际的 IServiceProvider 可以通过 ServiceCollection 构建一个来使用

//...code removed for brevity

var authServiceMock = new Mock<IAuthenticationService>();
authServiceMock
.Setup(_ => _.SignInAsync(It.IsAny<HttpContext>(), It.IsAny<string>(), It.IsAny<ClaimsPrincipal>(), It.IsAny<AuthenticationProperties>()))
.Returns(Task.FromResult((object)null));

var services = new ServiceCollection();
services.AddSingleton<IAuthenticationService>(authServiceMock.Object);

var controller = new UserController(svc, null) {
ControllerContext = new ControllerContext {
HttpContext = new DefaultHttpContext {
// How mock RequestServices?
RequestServices = services.BuildServiceProvider();
}
}
};

//...code removed for brevity

这样,如果有其他依赖项,它们可以被模拟并注册到服务集合中,以便可以根据需要解决它们。

关于c# - 如何对 HttpContext.SignInAsync() 进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47198341/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com