使用.NET Core 2.2,我正在尝试使用以这种方式启动的Identity Framework测试Razor页面
var user = await _userManager.GetUserAsync(User);
此通用类可以总结出许多在线解决方案:在IUserStore模拟中设置UserManager,在PageContext上设置User。
public class SetupContext<T> where T : IdentityUser<Guid>, new()
{
public Mock<IUserRoleStore<T>> MockUserStore { get; private set; }
public UserManager<T> SetupUserManager()
{
MockUserStore = new Mock<IUserStore<T>>().As<IUserRoleStore<T>>();
MockUserStore.Setup(x => x.FindByIdAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(
(string id, CancellationToken token) => new T()
{
Id = Guid.Parse(id),
UserName = "User name"
});
return new UserManager<T>(MockUserStore.Object, null, null, null, null, null, null, null, null);
}
public PageContext SetupPageContext()
{
var displayName = "User name";
var identity = new GenericIdentity(displayName);
var principle = new ClaimsPrincipal(identity);
var httpContext = new DefaultHttpContext()
{
User = principle
};
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var pageContext = new PageContext(actionContext)
{
ViewData = viewData
};
return pageContext;
}
}
问题是,这将无法正常工作。 GetUserAsync调用GetUserId,后者调用
principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType)
此声明未设置,实际上任何位置均未设置ID,因此无法返回用户或用户ID。然后,我将要访问与UserId相关的数据库数据以进行测试。
我花了很多时间进行搜索,但没有找到解决方案。看来我有90%的人在那里,但是我还需要正确设置测试吗?
我将运行的测试将按以下方式设置
private async Task<FreeTrialModel> SetupModelAsync()
{
_db = new RemoteHealingTechDbContext(InMemoryDbContext<RemoteHealingTechDbContext>.GetTestDbOptions());
await SeedData.Initialize(_db);
var _setup = new SetupContext<ApplicationUser>();
var userManager = _setup.SetupUserManager();
var pageContext = _setup.SetupPageContext();
return new FreeTrialModel(_db, userManager)
{
PageContext = pageContext
};
}
答案 0 :(得分:0)
经过进一步的挖掘,我终于找到了答案here
我必须使用包含Claims而不是GenericIdentity的ClaimsIdentity。替换
var identity = new GenericIdentity(displayName);
使用
var identity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, userName, null)
});
然后,FindByIdAsync方法使用UserName而不是UserId,因此我将声明更改为
MockUserStore.Setup(x => x.FindByIdAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(
(string userName, CancellationToken token) => new T()
{
Id = userId,
UserName = userName
});
整体解决方案
/// <summary>
/// Configures the .Net Core Identity Framework for unit testing.
/// </summary>
/// <typeparam name="T">The type of IdentityUser used for the framework.</typeparam>
/// <typeparam name="TKey">The data type of primary keys.</typeparam>
public class SetupContext<T, TKey> where T : IdentityUser<TKey>, new() where TKey : IEquatable<TKey>
{
/// <summary>
/// Returns the generated IUserRoleStore mock.
/// </summary>
public Mock<IUserRoleStore<T>> MockUserStore { get; private set; }
/// <summary>
/// Returns a UserManager based on a IUserRoleStore mock.
/// </summary>
/// <param name="userId">The UserId to set on generated IdentityUser objects.</param>
/// <returns>A new UserManager for unit testing.</returns>
public UserManager<T> SetupUserManager(TKey userId = default(TKey))
{
MockUserStore = new Mock<IUserStore<T>>().As<IUserRoleStore<T>>();
MockUserStore.Setup(x => x.FindByIdAsync(It.IsAny<string>(), It.IsAny<CancellationToken>())).ReturnsAsync(
(string userName, CancellationToken token) => new T()
{
Id = userId,
UserName = userName
});
return new UserManager<T>(MockUserStore.Object, null, null, null, null, null, null, null, null);
}
/// <summary>
/// Returns a PageContext to set on a page, containing a logged in user.
/// </summary>
/// <param name="userName">The user name to set on the ClaimsIdentity.</param>
/// <returns>A new PageContext object.</returns>
public PageContext SetupPageContext(string userName = "User name")
{
var identity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, userName, null)
});
var principle = new ClaimsPrincipal(identity);
var httpContext = new DefaultHttpContext()
{
User = principle
};
var modelState = new ModelStateDictionary();
var actionContext = new ActionContext(httpContext, new RouteData(), new PageActionDescriptor(), modelState);
var modelMetadataProvider = new EmptyModelMetadataProvider();
var viewData = new ViewDataDictionary(modelMetadataProvider, modelState);
var pageContext = new PageContext(actionContext)
{
ViewData = viewData
};
return pageContext;
}
}