I have a CustomPasswordValidator.cs file that overrides PasswordValidator
public class CustomPasswordValidator : PasswordValidator<AppUser>
{ //override the PasswordValidator functionality with the custom definitions
public override async Task<IdentityResult> ValidateAsync(UserManager<AppUser> manager, AppUser user, string password)
{
IdentityResult result = await base.ValidateAsync(manager, user, password);
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
//check that the username is not in the password
if (password.ToLower().Contains(user.UserName.ToLower()))
{
errors.Add(new IdentityError
{
Code = "PasswordContainsUserName",
Description = "Password cannot contain username"
});
}
//check that the password doesn't contain '12345'
if (password.Contains("12345"))
{
errors.Add(new IdentityError
{
Code = "PasswordContainsSequence",
Description = "Password cannot contain numeric sequence"
});
}
//return Task.FromResult(errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray()));
return errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
}
}
I am new to using Moq and xUnit. I am trying to create a unit test to ensure that the correct number of errors are produced (showing working code, with code that produced errors in comments):
//test the ability to validate new passwords with Infrastructure/CustomPasswordValidator.cs
[Fact]
public async void Validate_Password()
{
//Arrange
<Mock><UserManager<AppUser>> userManager = new <Mock><UserManager<AppUser>>(); //caused null exception, use GetMockUserManager() instead
<Mock><CustomPasswordValidator> customVal = new <Mock><CustomPasswordValidator>(); //caused null result object use customVal = new <CustomPasswordValidator>() instead
<AppUser> user = new <AppUser>
user.Name = "user"
//set the test password to get flagged by the custom validator
string testPwd = "Thi$user12345";
//Act
//try to validate the user password
IdentityResult result = await customVal.ValidateAsync(userManager, user, testPwd);
//Assert
//demonstrate that there are two errors present
List<IdentityError> errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();
Assert.Equal(errors.Count, 2);
}
//create a mock UserManager class
private Mock<UserManager<AppUser>> GetMockUserManager()
{
var userStoreMock = new Mock<IUserStore<AppUser>>();
return new Mock<UserManager<AppUser>>(
userStoreMock.Object, null, null, null, null, null, null, null, null);
}
The error occurs on the IdentityResult line, indicating that I cannot convert a Mock to UserManager and cannot convert Mock to AppUser class.
EDIT: changed to include GetMockUserManager() needed to mock a UserManagerClass in ASP.NET core (Mocking new Microsoft Entity Framework Identity UserManager and RoleManager)
With Moq you need call
.Object
on the mock to get the mocked object. You should also make the test async and await the method under test.You are also mocking the subject under test which in this case is cause the method under test to return null when called because it would not have been setup appropriately. You are basically testing the mocking framework at that point.
Create an actual instance of the subject under test
CustomPasswordValidator
and exercise the test, mocking the explicit dependencies of the subject under test to get the desired behavior.Read Moq Quickstart to get more familiar with how to use moq.