使用Xunit与MOQ:如何Mock返回List的泛型方法
如何Mock泛型仓储的GetItems方法返回指定List?
我正在使用.NET Core 3.1、MOQ与Xunit,采用工作单元(UOW)和仓储模式开发。我的泛型仓储中有如下GetItems方法,请问如何Mock该方法使其返回指定List?
泛型仓储中的GetItems方法
public async Task<List<TType>> GetItems<TType>(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderBy, Expression<Func<T, TType>> select) where TType : class { var Query = await _context.Set<T>().AsNoTracking().Where(predicate).OrderBy(orderBy).Select(select).ToListAsync(); return Query; }
我尝试的代码
_artikelAfwijkingen = new List<ArtAfwijking>() { new ArtAfwijking { Kd_Artikel = "Artikel_1", Kd_Instantie = "ACHM", LicNumber = 80, Nr_Filiaal = 0}, new ArtAfwijking { Kd_Artikel = "Artikel_1", Kd_Instantie = "ACHM", LicNumber = 0, Nr_Filiaal = 0}, new ArtAfwijking { Kd_Artikel = "Artikel_1", Kd_Instantie = "ACHM", LicNumber = 100, Nr_Filiaal = 0} }; artAfwijkingRepository.CallBase = true; artAfwijkingRepository.Setup(m => m.GetItems<ArtAfwijking>(It.IsAny<Expression<Func<ArtAfwijking, bool>>>(), It.IsAny<Expression<Func<ArtAfwijking, object>>>(), It.IsAny<Expression<Func<ArtAfwijking, ArtAfwijking>>>())) .Returns(Task.FromResult(_artikelAfwijkingen));; var repository = artAfwijkingRepository.Object; var artAfwijk = await repository.GetArtAfwijkingAsync("ARTIKEL_X", "ACHM", 80, 0, false);
ArtAfwijkingRepository中的GetArtAfwijkingAsync方法
public async Task<ArtAfwijking> GetArtAfwijkingAsync(string artikelCode, string instantieCode, int licentieNummer, short? filiaalNummer, bool overnemenOmschrijving) { List<ArtAfwijking> artikelAfwijkingen = await GetItems(a => a.Kd_Artikel == artikelCode && a.Kd_Instantie == instantieCode && a.Nr_Filiaal == filiaalNummer, a => a.Kd_Artikel, a => a); if (artikelAfwijkingen.Count == 1) return (artikelAfwijkingen[0]); return null; }
正确的Mock实现方案
你的代码核心问题在于CallBase = true会触发基类的真实方法调用,绕过Mock逻辑。调整后的代码如下:
_artikelAfwijkingen = new List<ArtAfwijking>() { new ArtAfwijking { Kd_Artikel = "Artikel_1", Kd_Instantie = "ACHM", LicNumber = 80, Nr_Filiaal = 0}, new ArtAfwijking { Kd_Artikel = "Artikel_1", Kd_Instantie = "ACHM", LicNumber = 0, Nr_Filiaal = 0}, new ArtAfwijking { Kd_Artikel = "Artikel_1", Kd_Instantie = "ACHM", LicNumber = 100, Nr_Filiaal = 0} }; // 移除CallBase = true,确保Mock生效 artAfwijkingRepository.Setup(m => m.GetItems<ArtAfwijking>( It.IsAny<Expression<Func<ArtAfwijking, bool>>>(), It.IsAny<Expression<Func<ArtAfwijking, object>>>(), It.IsAny<Expression<Func<ArtAfwijking, ArtAfwijking>>>())) .ReturnsAsync(_artikelAfwijkingen); // 使用ReturnsAsync简化异步返回值写法 var repository = artAfwijkingRepository.Object; var artAfwijk = await repository.GetArtAfwijkingAsync("ARTIKEL_X", "ACHM", 80, 0, false);
关键注意事项
- 移除
CallBase = true:该配置会让MOQ在没有匹配的Setup时调用基类真实方法,直接绕过你的Mock逻辑,导致无法返回预设的List。 - 使用
ReturnsAsync:MOQ提供的异步方法返回值快捷写法,比Task.FromResult更简洁直观。 - 泛型参数匹配:确保Setup中的
GetItems<ArtAfwijking>与实际调用的泛型参数一致,否则Mock不会生效。
如果需要验证传入的表达式是否符合预期,可以将It.IsAny<>替换为具体的表达式匹配逻辑,例如:
artAfwijkingRepository.Setup(m => m.GetItems<ArtAfwijking>( It.Is<Expression<Func<ArtAfwijking, bool>>>(expr => /* 这里编写表达式验证逻辑 */), It.IsAny<Expression<Func<ArtAfwijking, object>>>(), It.IsAny<Expression<Func<ArtAfwijking, ArtAfwijking>>>())) .ReturnsAsync(_artikelAfwijkingen);
但大多数单元测试场景下,使用It.IsAny<>已经足够覆盖需求。
内容的提问来源于stack exchange,提问作者user3552264
相关产品推荐
相关产品推荐

