#unit-testing #asp.net-core #asp.net-identity #moq #xunit
#модульное тестирование #asp.net-core #asp.net-identity #moq #xunit
Вопрос:
Я использую xUnit amp; Moq, и то, чего я пытаюсь достичь, обычно заключается в создании идентификатора пользователя, чтобы он хранился в базе данных Entity Framework в памяти.
Я установил функциональность начальных данных — она запускается, когда мой ASP.NET Приложение Core host запускается и работает безупречно — так что никаких проблем.
Но проблема возникает, когда я использую издевательский UserManager. Исключения не генерируются, пользователи просто не сохраняются.
Проверено при отладке тестов, DbContext
возвращает 0 пользователей, также UserManager.FindByNameAsync
выдает null
результат.
Интересно, в чем причина. Может ли это быть связано с тем, как я собираю UserManager в конструкторе SeedDataTest
класса?
public class SeedDataTest
{
private AppDbContext dbContext;
private UserManager<ApplicationUser> userManager;
private ITenantService tenantService;
public SeedDataTest()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "in_memory_db")
.Options;
dbContext = new AppDbContext(options);
var userStore = new UserStore<ApplicationUser>(dbContext);
userManager = new Mock<UserManager<ApplicationUser>>(
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)
.Object;
tenantService = new Mock<TenantService>(dbContext).Object;
}
[Fact]
public void Test1()
{
new TenantsCreator(dbContext).Create();
new UserCreator(dbContext, tenantService, userManager).Create(); // stuck here
new MembershipCreator(dbContext, userManager).Create();
// unfinished
}
}
И вот код из UserCreator
public class UserCreator
{
private AppDbContext _context;
private ITenantService _tenantService;
private UserManager<ApplicationUser> _userManager;
public UserCreator(
AppDbContext context,
ITenantService tenantService,
UserManager<ApplicationUser> userManager
)
{
_context = context;
_tenantService = tenantService;
_userManager = userManager;
}
public void Create()
{
Task.Run(async () => await CreateUsers()).ConfigureAwait(false).GetAwaiter().GetResult();
}
private async Task CreateUsers()
{
ApplicationUser hostAdminUser = _context.Users.FirstOrDefault(x => x.UserName.Equals(SetupConsts.Users.AdminJoe.UserName));
if (hostAdminUser == null)
{
hostAdminUser = new ApplicationUser()
{
FirstName = SetupConsts.Users.AdminJoe.FirstName,
LastName = SetupConsts.Users.AdminJoe.LastName,
UserName = SetupConsts.Users.AdminJoe.UserName,
Email = SetupConsts.Users.AdminJoe.Email,
EmailConfirmed = true,
PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(hostAdminUser, SetupConsts.Users.Passwords.Default)
};
await _userManager.CreateAsync(hostAdminUser);
}
ApplicationUser secondaryUser = _context.Users.FirstOrDefault(x => x.UserName.Equals(SetupConsts.Users.JohnRoe.UserName));
if (secondaryUser == null)
{
secondaryUser = new ApplicationUser()
{
FirstName = SetupConsts.Users.JohnRoe.FirstName,
LastName = SetupConsts.Users.JohnRoe.LastName,
UserName = SetupConsts.Users.JohnRoe.UserName,
Email = SetupConsts.Users.JohnRoe.Email,
EmailConfirmed = true,
PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(secondaryUser, SetupConsts.Users.Passwords.Default)
};
await _userManager.CreateAsync(secondaryUser);
}
}
}
Ответ №1:
мы используем макетные фреймворки, позволяющие нам создавать макетные (замещенные) зависимости, а также указывать, что возвращается из классов / интерфейсов, используемых в нашем SUT.
Хорошим вариантом использования для этого является сама база данных. Мы всегда хотим знать точное состояние объектов во время их тестирования, и единственный способ сделать это — выразить их содержимое самостоятельно.
Вот тут-то и появляется Moq. Одна из его особенностей заключается в том, что он позволяет нам указывать результат вызовов методов.
Я полагаю, что вы видите 0 возвращаемых результатов, потому что вы используете реализацию класса moq (которая фактически не вызывает реализованный класс). Чтобы получить результат, вам нужно будет выполнить некоторую настройку:
mockedClass.Setup(x => x.GetUserDetails(It.IsAny<int>())).Returns(new UserDetails());
Либо сделайте это таким образом, либо убедитесь, что вы передаете конкретную реализацию класса UserManager, а не издевательскую версию:
userManager = new UserManager<ApplicationUser>
Надеюсь, это поможет
Комментарии:
1. требуется конкретная реализация — это было абсолютно так, действительно, большое вам спасибо!