我正在用mongo db编写单元测试,我需要测试以某种方式处理从mongo返回的数据的方法。例如方法
IFindFluent<Transcript, Transcript> GetTranscriptByUserId(int userId);
应返回一些笔录。但是,它返回的接口具有几个道具-Filter
,Options
,Sort
等。
我要测试Paginane
类的方法Paginator<T>
public PaginatedObject<T> Paginate(IFindFluent<T,T> items, int limit, int page)
{
if (limit == 0)
{
limit = 10;
}
int count = (int)items.Count();
var lastPage = (count / limit) + 1;
if (page <= 0)
{
page = 1;
}
if (page > lastPage)
{
page = lastPage;
}
var request = items.Skip((page - 1) * limit).Limit(limit);
var itemsToReturn = request.ToList();
var pages = new PaginatedObject<T>
{
Entries = itemsToReturn,
Limit = limit,
Total = count,
Page = page
};
return pages;
}
第一个参数是接口IFindFluent<T,T>
项。因此,我应该在调用Count
,Skip
和Limit
时模拟它以返回项目。但是这些方法很容易被嘲笑。
mockIfindFluent = new Mock<IFindFluent<Transcript, Transcript>>();
mockIfindFluent.Setup(s => s.Limit(It.IsAny<int>())).Returns(mockIfindFluent.Object);
mockIfindFluent.Setup(i => i.Skip(It.IsAny<int>())).Returns(mockIfindFluent.Object);
mockIfindFluent.Setup(i => i.Count(CancellationToken.None)).Returns(3);
我打电话给ToList()
时遇到的实际问题。
我有一个例外,我无法模拟不属于模型的属性,依此类推。
从此https://gist.github.com/mizrael/a061331ff5849bf03bf2和对我有用的扩展实现中获得一些启发。我创建了IFindFluent接口的虚假实现,并且它依赖于IAsyncCursor接口,因此我也对该接口进行了虚假实现,并使用该虚假实现作为我想设置的模拟方法的回报。在该伪造的实现中,我已经初始化了一个可枚举的对象,并以我正在使用的方法将其返回。您仍然可以更具创造力,可以随心所欲地返回。到目前为止,这对我有用。
这里是伪造的实现。
public class FakeFindFluent<TEntity, TProjection> : IFindFluent<TEntity, TEntity>
{
private readonly IEnumerable<TEntity> _items;
public FakeFindFluent(IEnumerable<TEntity> items)
{
_items = items ?? Enumerable.Empty<TEntity>();
}
public FilterDefinition<TEntity> Filter { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public FindOptions<TEntity, TEntity> Options => throw new NotImplementedException();
public IFindFluent<TEntity, TResult> As<TResult>(MongoDB.Bson.Serialization.IBsonSerializer<TResult> resultSerializer = null)
{
throw new NotImplementedException();
}
public long Count(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<long> CountAsync(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public long CountDocuments(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<long> CountDocumentsAsync(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public IFindFluent<TEntity, TEntity> Limit(int? limit)
{
throw new NotImplementedException();
}
public IFindFluent<TEntity, TNewProjection> Project<TNewProjection>(ProjectionDefinition<TEntity, TNewProjection> projection)
{
throw new NotImplementedException();
}
public IFindFluent<TEntity, TEntity> Skip(int? skip)
{
throw new NotImplementedException();
}
public IFindFluent<TEntity, TEntity> Sort(SortDefinition<TEntity> sort)
{
throw new NotImplementedException();
}
public IAsyncCursor<TEntity> ToCursor(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<IAsyncCursor<TEntity>> ToCursorAsync(CancellationToken cancellationToken = default)
{
IAsyncCursor<TEntity> cursor = new FakeAsyncCursor<TEntity>(_items);
var task = Task.FromResult(cursor);
return task;
}
}
public class FakeAsyncCursor<TEntity> : IAsyncCursor<TEntity>
{
private IEnumerable<TEntity> items;
public FakeAsyncCursor(IEnumerable<TEntity> items)
{
this.items = items;
}
public IEnumerable<TEntity> Current => items;
public void Dispose()
{
//throw new NotImplementedException();
}
public bool MoveNext(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken = default)
{
return Task.FromResult(false);
}
}
这是我设置模拟方法以返回单元测试所需内容的方法。
mockParticipantRepository
.Setup(x => x.FindByFilter(It.IsAny<FilterDefinition<Participant>>()))
.Returns(new FakeFindFluent<Participant, Participant>(participantsByRelation));
我希望这会有所帮助。