Издевательский новый пользовательский интерфейс Microsoft Entity Framework UserManager и RoleManager
Кто-нибудь придумал удачное издевательское решение для UserManager
и RoleManager
? Я весь день бил головой о стену. Все, что я хочу сделать, - это обмануть объекты для использования в коллекции памяти, а не попадания в хранилище данных Entity Framework. Я просмотрел интернет и попробовал несколько разных подходов с помощью MOQ.
У меня создалось впечатление, что новый материал намного легче тестировать. Я что-то пропустил?
Ответы
Ответ 1
Кроме того, вы можете IUserStore<TUser>
интерфейс IUserStore<TUser>
который UserManager
принимает в качестве аргумента.
var userStore = new Mock<IUserStore<ApplicationUser>>();
var userManager = new UserManager(userStore.Object);
Как отмечает @Joe Brunscheon в комментарии ниже, UserManager обнаруживает поддержку других интерфейсов, таких как IUserPasswordStore и т.д. Вы также можете выполнить следующие действия:
var passwordManager = userStore.As<IUserPasswordStore<ApplicationUser>>()
.Setup(...).Returns(...);
Вам не нужно выставлять все эти данные сразу, вы можете просто помагать их по мере необходимости с помощью кода. На самом деле, UserStore, который использует EF для реализации IUserStore, реализует другие интерфейсы, а UserManager будет выполнять внутреннее обнаружение, чтобы убедиться, что эти интерфейсы реализованы, и, следовательно, поддерживаются дополнительные функции. К счастью, moq позволяет вам макетировать суррогат, который может реализовать множество интерфейсов, используя .As<T>()
.
Короче говоря, Microsoft.AspNet.Identity дает вам все, что вам нужно, чтобы использовать его без оболочки без кода в вашем коде. До тех пор, пока вы используете инъекцию зависимостей для создания экземпляра UserManager, вы можете спокойно протестировать его в модульных тестах, высмеивая интерфейсы, которые он потребляет, и передавая их через какой-то IUserStore<T>
moq, который дополняется для поддержки методов на других обнаруженных внутри интерфейса с помощью UserManager.
Ответ 2
Мне нравится обновлять решение этого вопроса для тех, кто работает с ядром 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, но до сих пор нет более изящного решения. Если вас интересуют другие параметры, посмотрите исходный код.
Ответ 3
Вы не сможете напрямую подключать 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 a class that 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.
}
}
Ответ 4
Чтобы развернуть ответ Rubito, вот как я сделал это для RoleManager:
public static Mock<RoleManager<ApplicationRole>> GetMockRoleManager()
{
var roleStore = new Mock<IRoleStore<ApplicationRole>>();
return new Mock<RoleManager<ApplicationRole>>(
roleStore.Object,null,null,null,null);
}
Ответ 5
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 == "[email protected]");
}
public override Task<string> GeneratePasswordResetTokenAsync(User user)
{
return Task.FromResult("---------------");
}
}