【发布时间】:2021-09-05 14:11:30
【问题描述】:
我正在尝试使用 Moq + Nunit 设置测试。
我正在使用存储库模式
public interface IRepository<T> where T : class
{
Task<List<T>> FindByConditionAsync(Expression<Func<T, bool>> expression);
Task<List<T>> GetAllAsync();
//...
}
public class Repository<TEntity, TContext> : IRepository<TEntity>
{
//...Omitted other code from this snippet
public async Task<List<TEntity>> FindByConditionAsync(Expression<Func<TEntity, bool>> expression)
{
return await _context.Set<TEntity>().Where(expression).ToListAsync();
}
}
public interface IUserRepository : IRepository<User>
{
}
public class UserRepository : Repository<User, MyDatabase>, IUserRepository
{
public UserRepository(MyDatabase context) : base(context)
{
}
}
我的测试文件
public class UserProviderTests
{
private IMapper _mapper;
private UserProvider _userProvider;
private Mock<MyDatabase> _mockContext;
private UserRepository _userRepository;
[SetUp]
public void Setup()
{
var user1Guid = Guid.NewGuid();
var user2Guid = Guid.NewGuid();
var data = new List<User>
{
new User
{
Id = user1Guid,
FirstName = "Optimus",
LastName = "Prime"
},
new User
{
Id = user2Guid,
FirstName = "John",
LastName = "Doe",
}
}.AsQueryable();
var mockSet = new Mock<DbSet<User>>();
mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var options = new DbContextOptionsBuilder<MyDatabase>()
.UseSqlServer("fakestring")
.Options;
_mockContext = new Mock<MyDatabase>(options);
_mockContext.Setup(c => c.Users).Returns(mockSet.Object);
_userRepository = new UserRepository(_mockContext.Object);
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<MappingProfile>();
});
_mapper = new Mapper(config);
_userProvider = new UserProvider(_mapper, _userRepository);
}
[Test]
public async Task GetUsers_ReturnsSingleUser()
{
var users = await _userProvider.FindUser("xxx");
Assert.AreEqual("xxx", users.FirstOrDefault()?.FirstName);
}
}
UserProvider 是我正在使用的一项服务,它使用 UserRepository 来执行 CRUD 操作。 但是当我尝试运行此测试时,我收到错误消息 -
System.ArgumentNullException:值不能为空。 (参数“来源”)
堆栈跟踪: Queryable.Where[TSource](IQueryable'1 源,Expression'1 谓词) Repository'2.FindByConditionAsync(Expression'1 表达式) 第48行
抱歉这个问题太长了,但我在这里遗漏了什么吗?我不明白为什么 TSource(USer object) 为空。
【问题讨论】:
-
IQueryables 很难模拟,所以如果你不想在那里重新实现很多逻辑,要么将其抽象出来,这样你就不必测试它,或者考虑使用 in-使用 EF Core 的内存数据库,而不是尝试模拟您的 DbSet。
-
还有几个第三库已经解决了这个问题。仅举几例:Moq.EntityFrameworkCore、EntityFrameworkCore3Mock、EntityFrameworkCore.Testing 等
标签: c# unit-testing nunit moq repository-pattern