是否有人为UserManager
和RoleManager
提出了成功的模拟解决方案?我整天都在靠墙打我的头。我想要做的就是模拟对象以使用内存集合而不是命中Entity Framework数据存储。我已经浏览了互联网并使用MOQ尝试了几种不同的方法。
我的印象是新东西更容易测试。我错过了什么吗?
答案 0 :(得分:35)
或者,您可以模拟IUserStore<TUser>
作为参数接受的UserManager
接口。
var userStore = new Mock<IUserStore<ApplicationUser>>();
var userManager = new UserManager(userStore.Object);
正如@Joe Brunscheon在下面的评论中指出的那样,UserManager检测到对其他接口的支持,例如IUserPasswordStore等。你也可以moq那些:
var passwordManager = userStore.As<IUserPasswordStore<ApplicationUser>>()
.Setup(...).Returns(...);
您不必一次性地删除所有这些内容,您可以根据需要通过测试代码对其进行调整。实际上,EF用于实现IUserStore的UserStore实现了其他接口,UserManager将进行内部检测以查看是否实现了这些接口,因此支持其他功能。幸运的是,moq允许您使用.As<T>()
模拟可以实现许多接口的代理。
简而言之,Microsoft.AspNet.Identity确实为您提供了在代码中无需使用包装器即可使用它所需的一切。只要您使用依赖注入来实例化您的UserManager,您就可以安全地在单元测试中模拟它消耗的接口并通过某种IUserStore<T>
moq传递它们,该moq被扩充以支持内部其他接口上的方法用户管理器检测到。
答案 1 :(得分:23)
我喜欢为任何使用asp.net核心的人更新此问题的解决方案:
private Mock<UserManager<ApplicationUser>> GetMockUserManager()
{
var userStoreMock = new Mock<IUserStore<ApplicationUser>>();
return new Mock<UserManager<ApplicationUser>>(
userStoreMock.Object, null, null, null, null, null, null, null, null);
}
是的,8次null,但到目前为止还没有更优雅的解决方案。 如果您对其他参数感兴趣,请查看source code。
答案 2 :(得分:2)
您将无法直接模拟UserManager或RoleManager。但是,你可以做的是模拟一个使用它们的对象。
例如:
public interface IWrapUserManager
{
UserManager WrappedUserManager {get; set;}
//provide methods / properties that wrap up all UserManager methods / props.
}
public class WrapUserManager : IWrapUserManager
{
UserManager WrappedUserManager {get; set;}
//implementation here. to test UserManager, just wrap all methods / props.
}
//Here's a class that's actually going to use it.
public class ClassToTest
{
private IWrapUserManager _manager;
public ClassToTest(IWrapUserManager manager)
{
_manager = manager;
}
//more implementation here
}
嘲笑:
[TestClass]
public class TestMock
{
[TestMethod]
public void TestMockingUserManager()
{
var mock = new Mock<IWrapUserManager>();
//setup your mock with methods and return stuff here.
var testClass = new ClassToTest(mock.Object); //you are now mocking your class that wraps up UserManager.
//test your class with a mocked out UserManager here.
}
}
答案 3 :(得分:2)
为了扩展Rubito的answer,以下是我为RoleManager做的事情:
public static Mock<RoleManager<ApplicationRole>> GetMockRoleManager()
{
var roleStore = new Mock<IRoleStore<ApplicationRole>>();
return new Mock<RoleManager<ApplicationRole>>(
roleStore.Object,null,null,null,null);
}
答案 4 :(得分:2)
public class FakeUserManager : UserManager<User>
{
public FakeUserManager()
: base(new Mock<IUserStore<User>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<User>>().Object,
new IUserValidator<User>[0],
new IPasswordValidator<User>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<User>>>().Object,
new Mock<IHttpContextAccessor>().Object)
{ }
public override Task<User> FindByEmailAsync(string email)
{
return Task.FromResult(new User{Email = email});
}
public override Task<bool> IsEmailConfirmedAsync(User user)
{
return Task.FromResult(user.Email == "test@test.com");
}
public override Task<string> GeneratePasswordResetTokenAsync(User user)
{
return Task.FromResult("---------------");
}
}
答案 5 :(得分:1)
这是Rubito对NET Core 3.1的出色回答的明确版本,其中没有null,null和null:
public static UserManager<TUser> GetUserManager<TUser>(IUserStore<TUser> store = null)
where TUser : class
{
// https://github.com/aspnet/Identity/blob/master/test/Shared/MockHelpers.cs
store = store ?? new Mock<IUserStore<TUser>>().Object;
var options = new Mock<IOptions<IdentityOptions>>();
var idOptions = new IdentityOptions();
idOptions.Lockout.AllowedForNewUsers = false;
options.Setup(o => o.Value).Returns(idOptions);
var userValidators = new List<IUserValidator<TUser>>();
var validator = new Mock<IUserValidator<TUser>>();
userValidators.Add(validator.Object);
var pwdValidators = new List<PasswordValidator<TUser>>();
pwdValidators.Add(new PasswordValidator<TUser>());
var userManager = new UserManager<TUser>(
store: store,
optionsAccessor: options.Object,
passwordHasher: new PasswordHasher<TUser>(),
userValidators: userValidators,
passwordValidators: pwdValidators,
keyNormalizer: new UpperInvariantLookupNormalizer(),
errors: new IdentityErrorDescriber(),
services: null,
logger: new Mock<ILogger<UserManager<TUser>>>().Object);
validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>()))
.Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
return userManager;
}