我正在尝试使用DepartmentSerive.SearchAsync(string name)
测试方法Moq
。到目前为止,我已经按照msdn tutorial了解了如何模拟DbSet
和ApplicationDbContext
类。
首先,我复制了DbAsyncQueryProvider
实现,因此我可以使用异步方法。
然后我实施了我的DepartmentService : Service<TEntity>
课程。
public class DepartmentService : Service<Department>
{
public DepartmentService(ApplicationDbContext db) : base(db) { }
public async Task<ICollection<Department>> SearchAsync(string name)
{
if (String.IsNullOrEmpty(name))
{
return await AllAsync();
}
return await db.Departments
.Where(d => d.Name.ToLower().Contains(name.ToLower()))
.OrderBy(d => d.Name)
.ToListAsync();
}
}
Service<TEntity>
是一项通用服务,其中包含AllSync
,Insert
,Update
,Delete
等方法,但相关部分位于此处:
public abstract class Service<TEntity> where TEntity : class
{
public virtual async Task<ICollection<TEntity>> AllAsync()
{
return await db.Set<TEntity>().ToListAsync();
}
}
我有一个Setup
方法:
[TestInitialize]
public void Setup()
{
var data = new List<Department>
{
new Department { Id = 1, Name = "Computer Science" },
new Department { Id = 2, Name = "Political Science" },
new Department { Id = 3, Name = "Physics" },
new Department { Id = 4, Name = "Mathematics" },
}.AsQueryable();
var set = new Mock<DbSet<Department>>();
set.As<IDbAsyncEnumerable<Department>>().Setup(m => m.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<Department>(data.GetEnumerator()));
set.As<IQueryable<Department>>().Setup(m => m.Provider).Returns(new TestDbAsyncQueryProvider<Department>(data.Provider));
set.As<IQueryable<Department>>().Setup(m => m.Expression).Returns(data.Expression);
set.As<IQueryable<Department>>().Setup(m => m.ElementType).Returns(data.ElementType);
set.As<IQueryable<Department>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
context = new Mock<ApplicationDbContext>();
context.Setup(c => c.Set<Department>()).Returns(set.Object);
context.Setup(c => c.Departments).Returns(set.Object);
}
最后我的测试:
[TestMethod]
public async Task SearchWithEmptyString()
{
var service = new DepartmentService(context.Object);
var result = await service.SearchAsync(null);
Assert.AreEqual(4, result.Count);
result = await service.SearchAsync("");
Assert.AreEqual(4, result.Count);
}
我的测试应该通过,考虑null
和""
将由SearchAsync()
以相同的方式处理,但它实际上在第二个Assert.AreEqual(4, result.Count);
上失败。出于某种原因,服务中对AllAsync()
的第一次调用返回整个列表,但第二次返回一个空列表,就像AllAsync()
返回元素一样,但也清空了进程中的列表。
当我使用真实数据库时,不会发生此问题。我在AllAsync()
写了两个顺序DepartmentController
,第二个仍然返回正确的数据。
我做错了什么,嘲笑列表或设置测试?
答案 0 :(得分:1)
我能够解决问题。事实证明,在与IEnumerator<T> _inner
的Microsoft实现中包含的internal class TestDbAsyncEnumerator<T>
进行交互后,属性Current
未被重置,保持在最后位置,因此被评估为{{ 1}}在null
的第二次调用中。
因此,只需在类await db.Set<TEntity>().ToListAsync();
的方法_inner.Reset();
中添加Dispose()
即可解决问题!您必须将其放在try-catch块中,考虑TestDbAsyncEnumerator<T>
未实现AsyncQueryProvider
方法,并且在进行查询后也会调用方法Reset()
。
Dispose()