【发布时间】:2020-02-17 09:39:45
【问题描述】:
我正在尝试使用 XUnit 项目对我的 ASP.NET Core WebAPI 执行单元测试。我正在使用 3 层架构,其中每一层都在不同的类库项目中,并且依赖项通过依赖注入来解决。一切正常。但是当我想执行单元测试时,我陷入了对逻辑层和数据层的模拟。当我运行测试时,我得到了这个错误:
消息:System.ArgumentException:无法为接口模拟传递构造函数参数。
我的模拟对象在这个类中生成:
public static class MockObjects
{
public static Mock<UserManager<TUser>> GetUserManagerMock<TUser>() where TUser : IdentityUser
{
return new Mock<UserManager<TUser>>(
new Mock<IUserStore<TUser>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<TUser>>().Object,
new IUserValidator<TUser>[0],
new IPasswordValidator<TUser>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<TUser>>>().Object);
}
public static Mock<SignInManager<TUser>> GetSignInManagerMock<TUser>() where TUser : IdentityUser
{
return new Mock<SignInManager<TUser>>(
GetUserManagerMock<TUser>().Object,
new Mock<IHttpContextAccessor>().Object,
new Mock<IUserClaimsPrincipalFactory<TUser>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<ILogger<SignInManager<TUser>>>().Object,
new Mock<IAuthenticationSchemeProvider>().Object
);
}
public static Mock<RoleManager<TIdentityRole>> GetRoleManagerMock<TIdentityRole>() where TIdentityRole : IdentityRole
{
return new Mock<RoleManager<TIdentityRole>>(
new Mock<IRoleStore<TIdentityRole>>().Object,
new IRoleValidator<TIdentityRole>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<ILogger<RoleManager<TIdentityRole>>>().Object);
}
public static Mock<ApplicationDbContext> GetDbContextMock()
{
return new Mock<ApplicationDbContext>(new DbContextOptions<ApplicationDbContext>());
}
public static Mock<TRepository> GetRepositoryMock<TRepository>() where TRepository : class
{
return new Mock<TRepository>(GetDbContextMock().Object);
}
public static Mock<ISmsService> GetSmsServiceMock()
{
return new Mock<ISmsService>(GetRepositoryMock<SmsRepository>().Object);
}
public static Mock<IEmailService> GetEmailServiceMock()
{
return new Mock<IEmailService>(GetRepositoryMock<EmailRepository>().Object);
}
public static Mock<IProfileService> GetProfileServiceMock()
{
return new Mock<IProfileService>(GetRepositoryMock<ProfileRepository>().Object);
}
public static Mock<IAccountService> GetAccountServiceMock()
{
return new Mock<IAccountService>(
GetUserManagerMock<ApplicationUser>().Object,
GetSignInManagerMock<ApplicationUser>().Object,
GetSmsServiceMock().Object,
GetEmailServiceMock().Object,
new Mock<IConfiguration>().Object,
GetProfileServiceMock().Object
);
}
}
我在这篇博文之后实现了这个类: https://dejanstojanovic.net/aspnet/2019/september/unit-testing-repositories-in-aspnet-core-with-xunit-and-moq/
我的测试方法:
[Fact]
public async Task RegisterSimpleTest()
{
// Arrange
var mockService = MockObjects.GetAccountServiceMock().Object;
var controller = new AccountController(mockService);
var data = new EmailRegisterViewModel()
{
Email = "a@a.a",
Password = "123456",
ConfirmPassword = "123456"
};
// Act
var result = await controller.Register(data) as ObjectResult;
// Assert
Assert.NotNull(result);
Assert.Equal(200, result.StatusCode);
}
我要测试的控制器动作:
[HttpPost]
public async Task<IActionResult> Register([FromBody]EmailRegisterViewModel model)
{
if (!ModelState.IsValid)
{
var errors = ModelStateExtention.GetModelErrors(ModelState);
return BadRequest(errors);
}
var user = new ApplicationUser()
{
UserName = model.Email,
Email = model.Email
};
var result = await _accountService.EmailRegisterAsync(user, model.Password);
return StatusResultExtension<ActionMessage>.GetStatusResult(result);
}
如何执行单元测试?我做错了什么?
【问题讨论】:
-
控制器动作应该经过集成测试。为您的帐户服务等内容预留单元测试。
标签: c# unit-testing asp.net-core dependency-injection xunit.net