模拟新的Microsoft Entity Framework Identity UserManager和RoleManager

时间:2014-01-17 19:33:45

标签: c# entity-framework unit-testing moq asp.net-identity

是否有人为UserManagerRoleManager提出了成功的模拟解决方案?我整天都在靠墙打我的头。我想要做的就是模拟对象以使用内存集合而不是命中Entity Framework数据存储。我已经浏览了互联网并使用MOQ尝试了几种不同的方法。

我的印象是新东西更容易测试。我错过了什么吗?

6 个答案:

答案 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;
}
相关问题