Saltar al contenido

¿Cómo simular UserManager en las pruebas de .Net Core?

Esta reseña ha sido evaluado por nuestros expertos para que tengas la garantía de la veracidad de este ensayo.

Solución:

Sé que esto tiene meses, pero sigo volviendo a este hilo. Ampliaré mi propia respuesta sobre este tema porque solo señalar el ejemplo de GitHub de Haok es como decir: “Leer un libro”, ya que es enorme. No identifica el problema ni lo que debe hacer. Debe aislar un objeto Mock, pero no solo eso, sino que también debe ‘Configurar’ el método para ‘CreateAsync’. Así que pongamos esto en tres partes:

  1. Necesita BURLARSE si está utilizando MOQ o un marco similar para hacer una creación simulada del UserManager.
  2. Debe configurar los métodos de UserManager de los que espera obtener resultados.
  3. Opcionalmente, querrá inyectar alguna lista genérica de un Entity Framework Core 2.1 simulado o similar para que realmente pueda ver que una lista de usuarios de IDentity realmente aumenta o disminuye. No solo que UserManager tuvo éxito y nada más

Entonces, digamos que tengo un método auxiliar para devolver un UserManager simulado. Que está ligeramente alterado del código Haok:

public static Mock> MockUserManager(List ls) where TUser : class

    var store = new Mock>();
    var mgr = new Mock>(store.Object, null, null, null, null, null, null, null, null);
    mgr.Object.UserValidators.Add(new UserValidator());
    mgr.Object.PasswordValidators.Add(new PasswordValidator());

    mgr.Setup(x => x.DeleteAsync(It.IsAny())).ReturnsAsync(IdentityResult.Success);
    mgr.Setup(x => x.CreateAsync(It.IsAny(), It.IsAny())).ReturnsAsync(IdentityResult.Success).Callback((x, y) => ls.Add(x));
    mgr.Setup(x => x.UpdateAsync(It.IsAny())).ReturnsAsync(IdentityResult.Success);

    return mgr;

Qué es key a esto es que estoy inyectando un ‘TUser’ genérico que es lo que estaré probando y también inyectando una lista de esto. Similar a mi ejemplo de:

 private List _users = new List
 
      new ApplicationUser("User1", "[email protected]")  Id = 1 ,
      new ApplicationUser("User2", "[email protected]")  Id = 2 
 ;
    
 ...

 private _userManager = MockUserManager(_users).Object; 

Luego, finalmente estoy probando un patrón con un repositorio similar a esta implementación que quiero probar:

 public async Task CreateUser(ApplicationUser user, string password) => (await _userManager.CreateAsync(user, password)).Succeeded ? user.Id : -1;

Lo pruebo así:

 [Fact]
 public async Task CreateAUser()
 
      var newUser = new ApplicationUser("NewUser", "[email protected]");
      var password = "[email protected]!";

      var result = await CreateUser(newUser, password);

      Assert.Equal(3, _users.Count);
  

El key Lo que hice es que no solo “configuré” CreateAsync, sino que proporcioné una devolución de llamada para poder ver cómo se incrementa mi lista que inyecto. Espero que esto ayude a alguien.

aspnet / Identity es de código abierto, así que lo que puede hacer es ver cómo se burlan de él.

Así es como lo hacen: MockHelpers.cs

TestUserManager

public static UserManager TestUserManager(IUserStore store = null) where TUser : class

    store = store ?? new Mock>().Object;
    var options = new Mock>();
    var idOptions = new IdentityOptions();
    idOptions.Lockout.AllowedForNewUsers = false;
    options.Setup(o => o.Value).Returns(idOptions);
    var userValidators = new List>();
    var validator = new Mock>();
    userValidators.Add(validator.Object);
    var pwdValidators = new List>();
    pwdValidators.Add(new PasswordValidator());
    var userManager = new UserManager(store, options.Object, new PasswordHasher(),
        userValidators, pwdValidators, new UpperInvariantLookupNormalizer(),
        new IdentityErrorDescriber(), null,
        new Mock>>().Object);
    validator.Setup(v => v.ValidateAsync(userManager, It.IsAny()))
        .Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
    return userManager;

En .NetCore 2.2 tienes que hacerlo ligeramente diferente. Trátelo como una actualización de la respuesta de @Nick Chapsas.

En primer lugar, debe usar IUserPasswordStore en lugar de IUserStore. IUserPasswordStore hereda IUserStore, pero a UserManager le gustaría obtener IUserPasswordStore. De otra manera, algunas cosas no funcionarán.

Si desea probar el comportamiento real de UserManager (por ejemplo, CreateUserAsync), puede usar implementaciones reales de UserValidator y PasswordValidator. Es posible que desee asegurarse de que su método reacciona como se supone que debe para los errores de CreateUser.

Este es mi ejemplo actualizado:

UserManager CreateUserManager() where TUser : class

    Mock> userPasswordStore = new Mock>();
    userPasswordStore.Setup(s => s.CreateAsync(It.IsAny(), It.IsAny()))
        .Returns(Task.FromResult(IdentityResult.Success));

    var options = new Mock>();
    var idOptions = new IdentityOptions();

    //this should be keep in sync with settings in ConfigureIdentity in WebApi -> Startup.cs
    idOptions.Lockout.AllowedForNewUsers = false;
    idOptions.Password.RequireDigit = true;
    idOptions.Password.RequireLowercase = true;
    idOptions.Password.RequireNonAlphanumeric = true;
    idOptions.Password.RequireUppercase = true;
    idOptions.Password.RequiredLength = 8;
    idOptions.Password.RequiredUniqueChars = 1;

    idOptions.SignIn.RequireConfirmedEmail = false;

    // Lockout settings.
    idOptions.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    idOptions.Lockout.MaxFailedAccessAttempts = 5;
    idOptions.Lockout.AllowedForNewUsers = true;


    options.Setup(o => o.Value).Returns(idOptions);
    var userValidators = new List>();
    UserValidator validator = new UserValidator();
    userValidators.Add(validator);

    var passValidator = new PasswordValidator();
    var pwdValidators = new List>();
    pwdValidators.Add(passValidator);
    var userManager = new UserManager(userPasswordStore.Object, options.Object, new PasswordHasher(),
        userValidators, pwdValidators, new UpperInvariantLookupNormalizer(),
        new IdentityErrorDescriber(), null,
        new Mock>>().Object);

    return userManager;

Tenga en cuenta que UserPasswordStore tiene un método (CreateAsync) que debe burlarse si desea probar CreateAsync desde UserManager.

La configuración de contraseña y bloqueo se toma de mi proyecto. Deben mantenerse sincronizados con su configuración, para que pueda probar el dispositivo real.

Por supuesto, no prueba, por ejemplo, PasswordValidator, pero puede probar sus métodos, por ejemplo:

//Part of user service
public async Task Register(UserDto data)

    SystemUser user = ConvertDtoToUser(data);
    IdentityResult result = userManager.CreateAsync(user, data.Password);

    //some more code that is dependent on the result

Agradecemos que desees proteger nuestra labor ejecutando un comentario y puntuándolo te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *