如何模拟IFindFluent接口 [英] How to mock IFindFluent interface

查看:141
本文介绍了如何模拟IFindFluent接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用mongo db编写单元测试,我需要测试以某种方式处理从mongo返回的数据的方法.例如方法

I am writing unit tests with mongo db and I need to test somehow methods that works with data returned from mongo. For example method

IFindFluent<Transcript, Transcript> GetTranscriptByUserId(int userId);

应返回一些成绩单.但是,它返回的接口具有几个道具-FilterOptionsSort等.

Should return some transcript. But instead it returns interface that has couple of props - Filter, Options, Sort, and other.

我要测试Paginator<T>类的方法Paginane

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>项.因此,当我调用CountSkipLimit时,我应该模拟它以返回项目.但是这些方法很容易被嘲笑.

First param is interface IFindFluent<T,T> items. So, I should mock it to return items when I call Count, Skip and Limit. But these methods could be easily mocked.

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()时遇到的真正问题.

Real problem I have when I call ToList().

我有一个例外,我无法模拟不属于模型的属性,依此类推.

I got exception that I can not mock property that does not belong to model and so on.

推荐答案

从以下 https:中汲取灵感: //gist.github.com/mizrael/a061331ff5849bf03bf2 和对我有用的扩展实现.我创建了IFindFluent接口的虚假实现,并且它依赖于IAsyncCursor接口,因此我也对该接口进行了虚假实现,并使用该虚假实现作为我想设置的模拟方法的回报.在该伪造的实现中,我已经初始化了一个可枚举的对象,并以我正在使用的方法将其返回.您仍然可以更有创造力,可以随心所欲地返回.到目前为止,这对我有用.

Took some inspiration from this https://gist.github.com/mizrael/a061331ff5849bf03bf2 and extended implementation which worked for me. I have created a fake implementation of the IFindFluent interface and it had a dependency on the IAsyncCursor interface, so I did a fake implementation of that also and using that in return of mock method I wanted to set up. In that fake implementation, I have initialized an enumerable and returned that in a method I am using. You can still be more creative and play around whatever you want to return. So far this worked for me.

这是一个伪造的实现.

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);
    }
}

这是我设置模拟方法以返回单元测试所需内容的方法.

Here is how I set up my mock method to return what I wanted for my unit testing.

mockParticipantRepository
                .Setup(x => x.FindByFilter(It.IsAny<FilterDefinition<Participant>>()))
                .Returns(new FakeFindFluent<Participant, Participant>(participantsByRelation));

我希望这会有所帮助.

I hope this is helpful.

这篇关于如何模拟IFindFluent接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆