Moq usermanager отсутствует IUserEmailStore - PullRequest
3 голосов
/ 10 апреля 2019

что я тестирую.

Это проект сервера идентификации с входом в федеративный шлюз.Я не управляю этим шлюзом, и у меня возникают проблемы с ними, которые не возвращают мне правильные утверждения о том, что мне нужно проверить логины пользователей.Я хотел бы быть в состоянии проверить, что я могу обработать эти ошибки.

Например, отсутствует требование по электронной почте без того, что я не могу войти в систему пользователя.

Я создал тест, в котором проверяется, что в заявке на электронную почту пропущено сообщение об ошибке (работает нормально)

Теперь я пытаюсь проверить другую сторону.Если утверждения действительно есть, он должен вернуть пользователя, который соответствует возвращенным утверждениям.

Метод, который мы тестируем

public static async Task<(ApplicationUser user, string provider, string providerUserUserName, IEnumerable<Claim> claims, string message)> FindUserFromExternalProvider(AuthenticateResult result, UserManager<ApplicationUser> userManager, ILogger<SegesExternalController> logger)
    {
        var externalUser = result.Principal;

        // try to determine the unique id of the external user (issued by the provider)
        var eMailClaim = externalUser.FindFirst(SegesSettingsConstants.SegesEmailClaimName);

        if(eMailClaim == null) return (null, null, null, null, $"{SegesSettingsConstants.SegesEmailClaimName} claim not found.");

        // remove the user id claim so we don't include it as an extra claim if/when we provision the user
        var claims = externalUser.Claims.ToList();
        claims.LogSegesClaims(logger);

        claims.Remove(eMailClaim);
        // Should we remove more claims
        var provider = result.Properties.Items["scheme"];
        var providerUserUserName = eMailClaim.Value;

        var user = await userManager.FindByEmailAsync(providerUserUserName);  // Test Breaks here

        return (user, provider, providerUserUserName, claims, null);
    }

Проверка

[Fact]
public async void Federated_login_with_email_claim_return_no_error()
    {
        // Arrange

        var principal = new ClaimsPrincipal();
        principal.AddIdentity(new ClaimsIdentity(
            new Claim[] {
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "Testbruger til André"),
                new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", @"PROD\Salg43"),
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode", "8200"),
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality", "Aarhus N"),
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "test@email.com"),
            },
            "FakeScheme"));
        var authenticateResult = AuthenticateResult.Success(new AuthenticationTicket(principal, new AuthenticationProperties() { Items = { { "scheme", "fed" } } }, "FakeScheme"));


        var exprectUser = new ApplicationUser()
        {
            UserName = "test@email.com",
            NormalizedUserName = "TEST@EMAIL.COM",
            NormalizedEmail = "TEST@EMAIL.COM",
            Email = "test@email.com",
            Id = 123,
            EmailConfirmed = true
        };

        var mockEmailStore = new Mock<IUserEmailStore<ApplicationUser>>();
        var mockQueryableUserStore = new Mock<IQueryableUserStore<ApplicationUser>>();

        var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
        mockUserStore.Setup(x => x.FindByIdAsync(exprectUser.Id.ToString(), CancellationToken.None)).ReturnsAsync(exprectUser);
        var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null,  null, null, null, null, null);


        var logger = new Logger<ExternalController>(new LoggerFactory());

        // Act
        var (user, provider, providerUserUserName, claims, errorMessage) = await AuthorizationHelpers.FindUserFromExternalProvider(authenticateResult, userManager, logger);

        // Assert
        user.ShouldNotBeNull();
    }

проблема с выше.

Я пытаюсь moq usermanager для моего модульного теста

var exprectUser = new ApplicationUser()
        {
            UserName = "test@email.com",
            NormalizedUserName = "TEST@EMAIL.COM",
            NormalizedEmail = "TEST@EMAIL.COM",
            Email = "test@email.com",
            Id = 123,
            EmailConfirmed = true
        };

var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
mockUserStore.Setup(x => x.FindByIdAsync(exprectUser.Id.ToString(), CancellationToken.None)).ReturnsAsync(exprectUser);
var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null,  null, null, null, null, null);

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

var findUser = await userManager.FindByEmailAsync("test@test.com");

выдает ошибку

Сообщение: System.NotSupportedException: Store не реализует IUserEmailStore.

Как мне реализовать IUserEmailStore в моем moq usermanager?

Мой проект модульного тестирования содержит новейший пакет EntityFramework.

Попытка другого способа.

var founduser = userManager.Users.FirstOrDefault(e => e.Email.Equals("test@test.com", StringComparison.InvariantCultureIgnoreCase));

приводит к

System.NotSupportedException: Store не реализует IQueryableUserStore.

Я думаю, что я должен ошибаться.

Обновление от комментария

Хорошо, я могу создать IUserEmailStore, но я не уверен, что мне с ним делать

var mockEmailStore = new Mock<IUserEmailStore<ApplicationUser>>();

Ответы [ 2 ]

1 голос
/ 10 апреля 2019

Хорошо, с обновленным вопросом, проблема заключается в

var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null,  null, null, null, null, null);

Это не создание макета, а фактический экземпляр UserManager<T>.

Вам нужно будет сделать

var userManagerMock = new Mock<UserManager<ApplicationUser>>(mockUserStore.Object, null, null, null,  null, null, null, null, null);

затем выполните настройку

userManagerMock.Setup(um => um.FindByEmailAsync("test@email.com)).Returns(exprectUser)

и передайте userManagerMock.Object своему

var (user, provider, providerUserUserName, claims, errorMessage) = await AuthorizationHelpers.FindUserFromExternalProvider(authenticateResult, userManagerMock.Object, logger);

При издевательстве вы никогда не захотите вызывать new для внешней зависимости и вместо этого смоделировать ее, поскольку с тех пор вы не можете изменить ее поведение для конкретного теста. UserManager<T> должен иметь все или большинство общедоступных свойств как виртуальные, чтобы их можно было переопределить.

1 голос
/ 10 апреля 2019

Мне удалось создать полноценный пользовательский менеджер moq, который позволяет мне искать по электронной почте

 public class MoqUserManager : UserManager<ApplicationUser>
    {
        public MoqUserManager(IUserStore<ApplicationUser> userStore) : base(userStore,
                new Mock<IOptions<IdentityOptions>>().Object,
                new Mock<IPasswordHasher<ApplicationUser>>().Object,
                new IUserValidator<ApplicationUser>[0],
                new IPasswordValidator<ApplicationUser>[0],
                new Mock<ILookupNormalizer>().Object,
                new Mock<IdentityErrorDescriber>().Object,
                new Mock<IServiceProvider>().Object,
                new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
        { }

        public override Task<ApplicationUser> FindByEmailAsync(string email)
        {
            return Task.FromResult(new ApplicationUser { Email = email });
        }    
    }

, что дает мне

var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
mockUserStore.Setup(x => x.FindByIdAsync(exprectUser.Id.ToString(), CancellationToken.None)).ReturnsAsync(exprectUser);
var userManager = new FakeUserManager(mockUserStore.Object);

Так что теперь я могу убедиться, что с моего сервера идентификации возвращается соответствующий пользователь, соответствующий федеративному пользователю входа в систему.

...