Как я могу издеваться над базовым методом при тестировании производного класса - PullRequest
1 голос
/ 29 марта 2020

У меня проблема с тем, что я хочу написать модульный тест пользовательской функции в моей службе пользователя. Но эта пользовательская служба является производной от asp. net основного идентификатора пользователя. Я хочу расширить функциональность менеджера пользователей, поэтому я получил его. Поэтому я хочу проверить метод CreateCRohMUserAsyn c

    public class UserService : UserManager<User>, IUserService
{
    public UserService(IUserStore<User> store,
        IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<User> passwordHasher,
        IEnumerable<IUserValidator<User>> userValidators,
        IEnumerable<IPasswordValidator<User>> passwordValidators,
        ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<User>> logger) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
    {
    }

    public async Task<IdentityResult> CreateCRohMUserAsync(User user)
    {
        PasswordGenerator pwGenerator = new PasswordGenerator();
        var password = pwGenerator.Generate();

        user.UserName = GetUniqueUserName(user.FirstName, user.LastName);

        var result = await base.CreateAsync(user, password);

        if (result.Succeeded)
        {
            //TODO: send mail to created user                
        }

        return result;
    }


    public string GetUniqueUserName(string firstName, string lastName)
    {
        if (string.IsNullOrEmpty(firstName))
        {
            throw new ArgumentNullException(nameof(firstName), "firstName can not be null");
        }
        if (string.IsNullOrEmpty(lastName))
        {
            throw new ArgumentNullException(nameof(lastName), "lastName can not be null");
        }

        return lastName + firstName.Substring(0, 2) + Users.Count() + 1;
    }
}

}

В моем модульном тесте я хочу смоделировать base.CreateAsyn c (пользователь, пароль) и функциональность Users.Count () моего базового класса. Но я не знаю, как это сделать. Или моя реализация неверна? Как я могу протестировать этот метод?

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Как вы используете moq .

Сначала вам нужно удалить ключевое слово base в CreateCRohMUserAsync:

var result = await CreateAsync(user, password); // Previously base.CreateAsync

Если оно присутствует, реализация базового класса всегда вызывается - mocking CreateAsync будет иметь без эффекта (moq проверяет методы, переопределяя их).

После удаления base вы можете проверить CreateCRohMUserAsync следующим образом:

[Fact]
public async void CreateCRohMUserAsync_DoesSomething()
{
    // Arrange
    ...
    Mock<UserService> mockTestSubject = new Mock<UserService>(...); // Pass services you'd normally pass to the UserService constructor
    mockTestSubject.CallBase = true; // So when you call CreateCRohMUserAsync, the logic you defined runs
    mockTestSubject.Setup(t => t.CreateAsync(...)).ReturnsAsync(...); // Mock CreateAsync
    // If GetUniqueUserName is virtual, you can mock it too    
    // mockTestSubject.Setup(t => t.GetUniqueUserName(...)).Returns(...);

    // Act
    IdentityResult result = await mockTestSubject.Object.CreateCRohMUserAsync(...);

    // Assert
    ...
}

Тот же шаблон будет работать для GetUniqueUserName ,

По существу:

  • Смоделируйте ваш производный класс, чтобы вы могли настроить виртуальных членов вашего базового класса.
  • Установите для CallBase значение true, чтобы вы могли запустить logi c, который вы определили в производном классе.
1 голос
/ 29 марта 2020

В соответствии с примером кода, я бы порекомендовал вам изменить наследование на композицию, поскольку вы используете только методы из базового класса, а не переопределять любые.

interface IUserManager
{
    IdentityResult CreateAsync();
}

class DefaultUserManager : IUserManager
{
    public DefaultUserManager(UserManager<User> manager)
    {
    }

    public IdentityResult CreateAsync()
    {
        // Call UserManager<User>
    }
}

public class UserService : IUserService
{
    private readonly IUserManager _userManager;

    public UserService(IUserManager userManager, ...)
    {
        _userManager = userManager;
    }

    public async Task<IdentityResult> CreateCRohMUserAsync(User user)
    {
        var result = await _userManager.CreateAsync();
        return result;
    }
}

Я бы абстрагировал использование UserManager<User> в интерфейс под названием IUserManager, и реализация все еще использует UserManager<User>. Ваш UserService, однако, вызывает интерфейс, так что в своем модульном тесте вы могли просто предоставить имитированный экземпляр IUserManager и избежать вызова UserManager<User>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...