我如何在 MVC 6 中 stub/mock AuthenticationManager?
How do I stub/mock AuthenticationManager in MVC 6?
我正在尝试对直接与 this.HttpContext.Authentication
交互以进行身份验证的 MVC 6 控制器进行单元测试。我没有使用身份框架,而是直接与 Cookie 身份验证中间件交互。
根据我在 MS 看到的一些示例,我一直在使用 DefaultHttpContext 进行测试。问题是 DefaultHttpContext 上的 AuthenticationManager 属性 是只读的,所以我不确定如何模拟它。
如果我不模拟它,我会在调用时收到一条错误消息,指出 "No authentication handler is configured to handle the scheme: Cookies" 在我的测试中:
HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, authProperties);
我遇到了同样的问题,我终于通过某种程度的模拟解决了
我用起订量
var claimPrincipal = new ClaimsPrincipal();
var mockAuth = new Mock<AuthenticationManager>();
mockAuth.Setup(c => c.SignInAsync("YourScheme", claimPrincipal)).Returns(Task.FromResult("done"));
var mockContext = new Mock<HttpContext>();
mockContext.Setup(c => c.Authentication).Returns(mockAuth.Object);
var fakeActionContext = new ActionContext(mockContext.Object, new RouteData(), new ControllerActionDescriptor());
var contContext = new ControllerContext(fakeActionContext);
然后将该控制器上下文传递给您要测试的控制器
var controller = new TestedController(Your attribute)
{
ControllerContext = contContext
};
微软现在弃用了接受的答案,微软建议不要使用 AuthenticationManager 而是使用扩展方法。下面是一个替代方案。请注意,添加的另外两个服务是因为设置 RequestServices 删除了一些默认值,否则这些默认值将由 DefaultHttpContext 创建。
var context = new ControllerContext();
context.HttpContext = new DefaultHttpContext();
context.HttpContext.User = userMock.Object; // If needed
context.HttpContext.Session = sessionMock.Object; // If needed
var authManager = new Mock<IAuthenticationService>();
authManager.Setup(s => s.SignOutAsync(It.IsAny<HttpContext>(),
CookieAuthenticationDefaults.AuthenticationScheme,
It.IsAny<Microsoft.AspNetCore.Authentication.AuthenticationProperties>())).
Returns(Task.FromResult(true));
var servicesMock = new Mock<IServiceProvider>();
servicesMock.Setup(sp => sp.GetService(typeof(IAuthenticationService))).Returns(authManager.Object);
servicesMock.Setup(sp => sp.GetService(typeof(IUrlHelperFactory))).Returns(new UrlHelperFactory());
servicesMock.Setup(sp => sp.GetService(typeof(ITempDataDictionaryFactory))).Returns(new TempDataDictionaryFactory(new SessionStateTempDataProvider()));
context.HttpContext.RequestServices = servicesMock.Object;
// Use context to pass to your controller
这就是使用 FakeItEasy 的方法:
var actionContext = new ActionContext
{
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
ActionDescriptor = new ControllerActionDescriptor()
};
// Creating AuthenticationService and Return calls for the Authentication factory
var authManager = A.Fake<IAuthenticationService>();
var authProperties = new Microsoft.AspNetCore.Authentication.AuthenticationProperties();
var servicesMock = A.Fake<IServiceProvider>();
A.CallTo(() => authManager.SignOutAsync(actionContext.HttpContext, CookieAuthenticationDefaults.AuthenticationScheme, authProperties)).Returns(Task.FromResult(true));
A.CallTo(() => servicesMock.GetService(typeof(IAuthenticationService))).Returns(authManager);
A.CallTo(() => servicesMock.GetService(typeof(IUrlHelperFactory))).Returns(new UrlHelperFactory());
A.CallTo(() => servicesMock.GetService(typeof(ITempDataDictionaryFactory))).Returns(new TempDataDictionaryFactory(new SessionStateTempDataProvider()));
var concon = new ControllerContext(actionContext);
concon.HttpContext.RequestServices = servicesMock;
我正在尝试对直接与 this.HttpContext.Authentication
交互以进行身份验证的 MVC 6 控制器进行单元测试。我没有使用身份框架,而是直接与 Cookie 身份验证中间件交互。
根据我在 MS 看到的一些示例,我一直在使用 DefaultHttpContext 进行测试。问题是 DefaultHttpContext 上的 AuthenticationManager 属性 是只读的,所以我不确定如何模拟它。
如果我不模拟它,我会在调用时收到一条错误消息,指出 "No authentication handler is configured to handle the scheme: Cookies" 在我的测试中:
HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, authProperties);
我遇到了同样的问题,我终于通过某种程度的模拟解决了 我用起订量
var claimPrincipal = new ClaimsPrincipal();
var mockAuth = new Mock<AuthenticationManager>();
mockAuth.Setup(c => c.SignInAsync("YourScheme", claimPrincipal)).Returns(Task.FromResult("done"));
var mockContext = new Mock<HttpContext>();
mockContext.Setup(c => c.Authentication).Returns(mockAuth.Object);
var fakeActionContext = new ActionContext(mockContext.Object, new RouteData(), new ControllerActionDescriptor());
var contContext = new ControllerContext(fakeActionContext);
然后将该控制器上下文传递给您要测试的控制器
var controller = new TestedController(Your attribute)
{
ControllerContext = contContext
};
微软现在弃用了接受的答案,微软建议不要使用 AuthenticationManager 而是使用扩展方法。下面是一个替代方案。请注意,添加的另外两个服务是因为设置 RequestServices 删除了一些默认值,否则这些默认值将由 DefaultHttpContext 创建。
var context = new ControllerContext();
context.HttpContext = new DefaultHttpContext();
context.HttpContext.User = userMock.Object; // If needed
context.HttpContext.Session = sessionMock.Object; // If needed
var authManager = new Mock<IAuthenticationService>();
authManager.Setup(s => s.SignOutAsync(It.IsAny<HttpContext>(),
CookieAuthenticationDefaults.AuthenticationScheme,
It.IsAny<Microsoft.AspNetCore.Authentication.AuthenticationProperties>())).
Returns(Task.FromResult(true));
var servicesMock = new Mock<IServiceProvider>();
servicesMock.Setup(sp => sp.GetService(typeof(IAuthenticationService))).Returns(authManager.Object);
servicesMock.Setup(sp => sp.GetService(typeof(IUrlHelperFactory))).Returns(new UrlHelperFactory());
servicesMock.Setup(sp => sp.GetService(typeof(ITempDataDictionaryFactory))).Returns(new TempDataDictionaryFactory(new SessionStateTempDataProvider()));
context.HttpContext.RequestServices = servicesMock.Object;
// Use context to pass to your controller
这就是使用 FakeItEasy 的方法:
var actionContext = new ActionContext
{
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
ActionDescriptor = new ControllerActionDescriptor()
};
// Creating AuthenticationService and Return calls for the Authentication factory
var authManager = A.Fake<IAuthenticationService>();
var authProperties = new Microsoft.AspNetCore.Authentication.AuthenticationProperties();
var servicesMock = A.Fake<IServiceProvider>();
A.CallTo(() => authManager.SignOutAsync(actionContext.HttpContext, CookieAuthenticationDefaults.AuthenticationScheme, authProperties)).Returns(Task.FromResult(true));
A.CallTo(() => servicesMock.GetService(typeof(IAuthenticationService))).Returns(authManager);
A.CallTo(() => servicesMock.GetService(typeof(IUrlHelperFactory))).Returns(new UrlHelperFactory());
A.CallTo(() => servicesMock.GetService(typeof(ITempDataDictionaryFactory))).Returns(new TempDataDictionaryFactory(new SessionStateTempDataProvider()));
var concon = new ControllerContext(actionContext);
concon.HttpContext.RequestServices = servicesMock;