使用xUnit测试服务时提示构造函数参数无匹配fixture数据,问题出在哪?
问题原因
你遇到的错误以及代码隐藏的问题一共有3处:
- HrbContext无法直接被Moq默认实例化
HrbContext没有无参构造函数,你的构造函数需要传入DbContextOptions<HrbContext>和IHttpContextAccessor两个参数,Moq默认调用无参构造函数创建代理类,找不到对应参数就会抛出你看到的参数不匹配错误。 - 异步方法没有做异步适配
你的服务GetAsync方法、仓储GetAsync方法的返回值都是Task<T>类型,你当前的测试是同步逻辑,既没有用await获取异步返回结果,也没有为Mock的仓储方法设置异步返回值。 - 断言逻辑错误
你没有await异步方法的情况下,拿到的result是Task<Phase>对象而不是Phase实体,直接取result.Id必然会报错。
修复方案
步骤1:修复HrbContext的Mock逻辑
给Moq传入HrbContext构造需要的两个参数即可,我们可以用内存数据库做单元测试的DbContext配置:
// 先Mock HrbContext需要的依赖 var mockHttpAccessor = new Mock<IHttpContextAccessor>(); var dbOptions = new DbContextOptionsBuilder<HrbContext>() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) .Options; // 传入构造参数创建HrbContext的Mock _context = new Mock<HrbContext>(dbOptions, mockHttpAccessor.Object);
如果你的PhaseService里没有直接调用HrbContext的逻辑,更推荐的方案是给HrbContext提取IHrbContext抽象接口,让服务依赖接口而不是具体实现,后续Mock不需要处理DbContext的构造逻辑。
步骤2:修复异步相关逻辑
- 测试方法返回值改为
async Task - 调用
GetAsync方法时加await - 仓储的Mock设置用
ReturnsAsync代替Returns适配异步返回值
修复后的完整代码
namespace HRB_Server.Tests.Services { public class PhaseServiceTest { private readonly Mock<IRepository<Phase>> _repository; private readonly Mock<IMapper> _mapper; private readonly Mock<HrbContext> _context; public PhaseServiceTest() { _repository = new Mock<IRepository<Phase>>(); _mapper = new Mock<IMapper>(); // 修复HrbContext Mock逻辑 var mockHttpAccessor = new Mock<IHttpContextAccessor>(); var dbOptions = new DbContextOptionsBuilder<HrbContext>() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; _context = new Mock<HrbContext>(dbOptions, mockHttpAccessor.Object); } [Fact] public async Task GetPhase_ActivePhaseObject_PhaseShouldExist() { // Arrange var newGuid = Guid.NewGuid(); var phase = GetSamplePhase(newGuid); // 用ReturnsAsync设置异步返回值 _repository.Setup(x => x.GetAsync(It.IsAny<Guid>())) .ReturnsAsync(phase); var phaseService = new PhaseService(_repository.Object, _mapper.Object, _context.Object); // Act 加await获取异步结果 var result = await phaseService.GetAsync(newGuid); // Assert Assert.Equal(phase.Id, result.Id); } // 补充你自己的SamplePhase生成逻辑即可 private Phase GetSamplePhase(Guid id) { return new Phase { Id = id }; } } }
内容的提问来源于stack exchange,提问作者Tempuslight
相关产品推荐
相关产品推荐

