如何对 HttpContext.SignInAsync() 进行单元测试? [英] How to unit test HttpContext.SignInAsync()?
问题描述
我在单元测试中遇到了一些问题.
DefaultHttpContext.RequestServices
是 null- 我尝试创建
AuthenticationService
对象,但我不知道要传递什么参数
我该怎么办?如何对 HttpContext.SignInAsync()
进行单元测试?
被测方法
public async Task登录(LoginViewModel vm, [FromQuery]string returnUrl){如果(模型状态.IsValid){var user = await context.Users.FirstOrDefaultAsync(u => u.UserName == vm.UserName && u.Password == vm.Password);如果(用户!= null){var claim = new List{新索赔(ClaimTypes.Name,user.UserName)};var identity = new ClaimsIdentity(claims, "HappyDog");//这里等待 HttpContext.SignInAsync(new ClaimsPrincipal(identity));return Redirect(returnUrl ?? Url.Action("Index", "Goods"));}}返回视图(vm);}
到目前为止我尝试过的.
[测试方法]公共异步任务 LoginTest(){使用 (var context = new HappyDogContext(_happyDogOptions)){await context.Users.AddAsync(new User { Id = 1, UserName = "test", Password = "password", FacePicture = "FacePicture" });等待 context.SaveChangesAsync();var controller = new UserController(svc, null){ControllerContext = 新的 ControllerContext{HttpContext = 新的 DefaultHttpContext{//如何模拟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代码>.那是你必须嘲笑的.
context.RequestServices.GetRequiredService().SignInAsync(上下文,方案,主体,属性);
您可以通过创建从使用的接口派生的类来手动创建假/模拟,也可以使用模拟框架,例如 起订量
//...为简洁起见删除了代码var authServiceMock = new Mock();authServiceMock.Setup(_ => _.SignInAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult((object)null));var serviceProviderMock = new Mock();服务提供者模拟.Setup(_ => _.GetService(typeof(IAuthenticationService))).Returns(authServiceMock.Object);var controller = new UserController(svc, null) {ControllerContext = 新的 ControllerContext {HttpContext = 新的 DefaultHttpContext {//如何模拟RequestServices?RequestServices = serviceProviderMock.Object}}};//...为简洁起见删除了代码
您可以在他们的快速入门中了解如何使用 Moq>
您可以像模拟其他依赖项一样轻松地模拟 HttpContext
,但如果存在不会导致不期望行为的默认实现,那么使用它可以使事情变得更简单
例如,通过ServiceCollection
IServiceProvider
//...为简洁起见删除了代码var authServiceMock = new Mock();authServiceMock.Setup(_ => _.SignInAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult((object)null));var services = new ServiceCollection();services.AddSingleton(authServiceMock.Object);var controller = new UserController(svc, null) {ControllerContext = 新的 ControllerContext {HttpContext = 新的 DefaultHttpContext {//如何模拟RequestServices?RequestServices = services.BuildServiceProvider();}}};//...为简洁起见删除了代码
这样,如果有其他依赖项,它们可以被模拟并注册到服务集合中,以便根据需要进行解析.
I ran into some problems with unit testing.
DefaultHttpContext.RequestServices
is null- I tried to create the
AuthenticationService
object, but I do not know what parameters to pass
What should I do? How to unit test HttpContext.SignInAsync()
?
Method under test
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);
}
What I have tried so far.
[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
is an extension method that uses RequestServices
, which is IServiceProvider
. That is what you must mock.
context.RequestServices
.GetRequiredService<IAuthenticationService>()
.SignInAsync(context, scheme, principal, properties);
You can either create a fake/mock manually by creating classes that derive from the used interfaces or use a mocking framework like 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
You can read up on how to use Moq here at their Quick start
You could just as easily mocked the HttpContext
as well like the other dependencies but if a default implementation exists that causes no undesired behavior, then using that can make things a lot simpler to arrange
For example, an actual IServiceProvider
could have been used by building one via 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
That way if there are other dependencies, they can be mocked and registered with the service collection so that they can be resolved as needed.
这篇关于如何对 HttpContext.SignInAsync() 进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!