我正在使用.Net Core 8,并且我有以下课程:
public class UserRepository : EfRepository<User>, IUserRepository
{
private readonly IJwtFactory _jwtFactory;
private readonly IJwtTokenValidator _jwtTokenValidator;
private readonly ITokenFactory _tokenFactory;
private readonly UserManager<AppUser> _userManager;
private readonly SignInManager<AppUser> _signInManager;
private readonly IMapper _mapper;
private readonly ILogger<UserRepository> _logger;
public UserRepository(ILogger<UserRepository> logger, UserManager<AppUser> userManager, SignInManager<AppUser> signInManager, IMapper mapper, AppDbContext appDbContext, IJwtFactory jwtFactory, IJwtTokenValidator jwtTokenValidator, ITokenFactory tokenFactory) : base(appDbContext)
{
_userManager = userManager;
_signInManager = signInManager;
_jwtFactory = jwtFactory;
_jwtTokenValidator = jwtTokenValidator;
_tokenFactory = tokenFactory;
_mapper = mapper;
_logger = logger;
}
public async virtual Task<MyResponse> MethodUnderTest(string id)
{
_userManager.DoSomeThing(); // Moq'ed object
_signInManager.DoSomeThins(); // Moq'ed object
}
<snip>
}
(1) 我应该
Moq
IUserRepository
还是物体?如何设置私有对象UserManager
和SignInManager
的函数调用?事实上,我如何将 Moq
和 UserManager
中的 SignInManager
传递给 Moq
ed IUserInterface
?
(2) 当我
Moq
UserRepository
对象时,将 Moq
对象传递给测试构造函数下的另一个对象时遇到以下异常:
System.ArgumentException : Can not instantiate proxy of class: Web.Api.Infrastructure.Data.Repositories.UserRepository.
Could not find a constructor that would match given arguments:
Castle.Proxies.ILogger`1Proxy
Castle.Proxies.UserManager`1Proxy
Castle.Proxies.SignInManager`1Proxy
Castle.Proxies.IMapperProxy
Castle.Proxies.AppDbContextProxy
Castle.Proxies.IJwtFactoryProxy
Castle.Proxies.IJwtTokenValidatorProxy
Castle.Proxies.ITokenFactoryProxy
(Parameter 'constructorArguments')
---- System.MissingMethodException : Constructor on type 'Castle.Proxies.UserRepositoryProxy' not found.
目标是能够最小化测试中涉及
UserRepository
方法的所有对象,并使用相应的方法Setup
进行测试。为此,我有一个类固定装置,它创建所有 moq
:
public class InfrastructureTestBase : IDisposable
{
public Mock<UserManager<AppUser>> UserManager { get; } = new Mock<UserManager<AppUser>>(Mock.Of<IUserStore<AppUser>>(), null, null, null, null, null, null, null, null);
public Mock<SignInManager<AppUser>> SignInManager { get; }
public Mock<ILogger<IUserRepository>> Logger { get; } = new Mock<ILogger<IUserRepository>>();
public Mock<IMapper> Mapper { get; } = new Mock<IMapper>();
public Mock<AppDbContext> AppDbContext { get; } = new Mock<AppDbContext>(new DbContextOptions<AppDbContext>());
public Mock<IJwtFactory> JwtFactory { get; } = new Mock<IJwtFactory>();
public Mock<IJwtTokenValidator> JwtTokenValidator { get; } = new Mock<IJwtTokenValidator>();
public Mock<UserRepository> UserRepository { get; private set; }
public Mock<ITokenFactory> TokenFactory { get; } = new Mock<ITokenFactory>();
public InfrastructureTestBase()
{
SignInManager = new Mock<SignInManager<AppUser>>(UserManager.Object, Mock.Of<IHttpContextAccessor>(), Mock.Of<IUserClaimsPrincipalFactory<AppUser>>(), null, null, null, null);
SignInManager.Setup(i => i.RefreshSignInAsync(It.IsAny<AppUser>()));
UserRepository = new Mock<UserRepository>(Logger.Object, UserManager.Object, SignInManager.Object, Mapper.Object, AppDbContext.Object, JwtFactory.Object, JwtTokenValidator.Object, TokenFactory.Object);
}
public void Dispose()
{
//throw new NotImplementedException();
}
}
如果您需要编写
UserRepository
类本身的测试,那么您可以创建其所有依赖项的 Test Doubles,如 OP 中所示。
无需创建
Mock<UserRepository>
,因为在这种情况下,UserRepository
对象是被测系统 (SUT):
var userRepository = new UserRepository(
Logger.Object,
UserManager.Object,
SignInManager.Object,
Mapper.Object,
AppDbContext.Object,
JwtFactory.Object,
JwtTokenValidator.Object,
TokenFactory.Object);
// Test code that exercises userRepository go here; e.g.
var actual = await userRepository.MethodUnderTest("foo");
另一方面,如果您需要测试另一个依赖于
IUserRepository
的类,只需创建它的测试替身:
var userRepositoryTD = new Mock<IUserRepository>();
// Configure one or more interface members if needed:
userRepositoryTD.Setup(r => r.MethodUnderTest("foo")).ReturnsAsync(whatever);
// Now pass the Test Double to your actual SUT
var sut = new MyClass(userRepositoryTD.Object);
// Then add test code that exercises the sut here...
userRepositoryTD.Object
是IUserRepository
接口的动态生成实现,它与具体的UserRepository
类没有任何关系。因此,在这种情况下,无需配置任何 UserRepository
类的依赖项(userManager
、userManager
等)。 userRepositoryTD.Object
没有这些依赖性。