问题
I am trying to work out how to add unit testing to my project. I thought it was best to start with a blank project and work it out from the start rather than adding it to my main project. Once I understand the process i figure i can start refactoring my project for adding testing.
web application
So i created a web application and added default user identity to it.
This gave me a start up looking like this
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Then i created a simple controller and passed the usermanager in the constructor.
[Route("api/[controller]")]
[ApiController]
public class SweetController : ControllerBase
{
private readonly UserManager<IdentityUser> _userManager;
public SweetController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
public async Task<int> NumberOfGummyBearsForUser(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
var userHasASweetTooth = await _userManager.IsInRoleAsync(user, "SweetTooth");
if (userHasASweetTooth)
{
return 100;
}
else
{
return 1;
}
}
}
Unit Test
The first thing i have been trying to do is mock this user manager but its not working.
public void Test1()
{
// Arrange
var mockUser = new Mock<UserManager<IdentityUser>>();
var userManager = new UserManager(mockRepo.Object); <-- error here see image below
var controller = new SweetController(userManager.Object);
// Act
var result = await controller.NumberOfGummyBearsForUser("123");
// Assert
Assert.Equal(100, result);
}
The error looks like this
I think i need to pass more to create this usermanager object but i am not sure what all the tutorials i have found use ApplicationUser and not IdentityUser so i am at a loss as to how i can mock this object.
回答1:
You just do
// Arrange
var mockUser = new Mock<UserManager<IdentityUser>>();
var controller = new SweetController(mockUser.Object);
You don't need
var userManager = new UserManager(mockRepo.Object); <-- error here see image below
at all. mockUser
is already the mocked UserManager<T>
, which you place a mocked instance via mock.Object
.
When you mock an object you don't have to instantiate it with all of its dependencies (that would be integration test), that's the point of mocking (along with making methods return a desired value and do behavior tests to make sure your tested code has called a specific method with specific parameter of the mocked object).
Of course per se the above code won't work, since you didn't setup any test conditions/returns for FindByIdAsync
and IsInRoleAsync
. You have to setup these with
mockUser.Setup( userManager => userManager.FindByIdAsync(It.IsAny<string>()))
.ReturnsAsync(new IdentityUser { ... });
mockUser.Setup( userManager => userManager.IsInRoleAsync(It.IsAny<IdentityUser>(), "SweetTooth"))
.ReturnsAsync(true);
Then whenever the mock is called it returns your predefined user and a predefined result.
回答2:
With Tseng's help I got this working. A fully working version of this is
controler
private readonly UserManager<IdentityUser> _userManager;
public SweetController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
public async Task<IdentityUser> GetUser(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
return user;
}
Test
[Fact]
public async Task Test1()
{
// Arrange
var store = new Mock<IUserStore<IdentityUser>>();
store.Setup(x => x.FindByIdAsync("123", CancellationToken.None))
.ReturnsAsync(new IdentityUser()
{
UserName = "test@email.com",
Id = "123"
});
var mgr = new UserManager<IdentityUser>(store.Object, null, null, null, null, null, null, null, null);
var controller = new SweetController(mgr);
// Act
var result = await controller.GetUser("123");
// Assert
Assert.NotNull(result);
Assert.Equal("123", result.Id);
}
I removed the role check just to get it working as basic as possible.
来源:https://stackoverflow.com/questions/55412776/how-to-mock-usermanageridentityuser