Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making IRedisCollection<T> more unit test friendly #474

Open
zulander1 opened this issue Aug 7, 2024 · 0 comments
Open

Making IRedisCollection<T> more unit test friendly #474

zulander1 opened this issue Aug 7, 2024 · 0 comments

Comments

@zulander1
Copy link
Contributor

I am in a scenario where we do not have access to a Redis instance when running the test. I have tried to see if I can override the IRedisConnectionProvider and return a custom IRedisCollection. However, the code in SearchExtensions is strongly typed. I have also tried using NSubstitute to return the custom class, but it resulted in the same error. I am not sure if this issue has helped successfully implemented the tests.

image

This is how to reproduce the issue

var _mockedObject = Substitute.ForPartsOf<ListConnectionProvider>();
_mockedObject.RedisCollection<Experience>(Arg.Any<bool>(), Arg.Any<int>()).Returns(f => { return new RedisCollectionTest<Experience>(); });
IRedisCollection<Experience> experiences = _mockedObject.RedisCollection<Experience>();
var filteredExperiences = await experiences.Where(x => x.Skills.Contains("C#")).ToListAsync();

[Document(StorageType = StorageType.Json, Prefixes = ["Test"], IndexName = "Test:idx")]
public class Experience
{
    [RedisIdField]
    [Indexed]
    public string Id { get; set; } = default!;

    [Indexed]
    public string[] Skills { get; set; } = default!;

    public override string ToString()
    {
        return string.Join(" ", Skills);
    }
}

public class ListConnectionProvider : IRedisConnectionProvider
{
    public IRedisConnection Connection => throw new NotImplementedException();

    public virtual RedisAggregationSet<T> AggregationSet<T>(int chunkSize = 100)
    {
        throw new NotImplementedException();
    }

    public virtual IRedisCollection<T> RedisCollection<T>(int chunkSize = 100) where T : notnull
    {
        return new RedisCollectionTest<T>();
    }

    public virtual IRedisCollection<T> RedisCollection<T>(bool saveState, int chunkSize = 100) where T : notnull
    {
        return new RedisCollectionTest<T>();
    }
}

public class RedisCollectionTest<T> : IRedisCollection<T>
{
    public IList<T> Items = new List<T>();

    public bool SaveState => throw new NotImplementedException();

    public RedisCollectionStateManager StateManager => throw new NotImplementedException();

    public int ChunkSize => throw new NotImplementedException();

    public Type ElementType => throw new NotImplementedException();

    public Expression Expression { get; init; }

    public IQueryProvider Provider => Items.AsQueryable().Provider;

    public Expression<Func<T, bool>>? BooleanExpression { get; set; }

    public bool Any()
    {
        return Items.Any();
    }

    public bool Any(Expression<Func<T, bool>> expression)
    {
        return Items.Any(expression.Compile());
    }

    public Task<bool> AnyAsync()
    {
        return Task.FromResult(Items.Any());
    }

    public Task<bool> AnyAsync(Expression<Func<T, bool>> expression)
    {
        return Task.FromResult(Items.Any(expression.Compile()));
    }

    public int Count(Expression<Func<T, bool>> expression)
    {
        return Items.Count(expression.Compile());
    }

    public int Count()
    {
        return Items.Count();
    }

    public Task<int> CountAsync()
    {
        return Task.FromResult(Items.Count());
    }

    public Task<int> CountAsync(Expression<Func<T, bool>> expression)
    {
        return Task.FromResult(Items.Count(expression.Compile()));
    }

    public void Delete(T item)
    {
        Items.Remove(item);
    }

    public void Delete(IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            Items.Remove(item);
        }
    }

    public Task DeleteAsync(T item)
    {
        Delete(item);
        return Task.CompletedTask;
    }

    public Task DeleteAsync(IEnumerable<T> items)
    {
        Delete(items);
        return Task.CompletedTask;
    }

    public T? FindById(string id)
    {
        return default;
    }

    public Task<T?> FindByIdAsync(string id)
    {
        return null;
    }

    public Task<IDictionary<string, T?>> FindByIdsAsync(IEnumerable<string> ids)
    {
        var dictionary = new Dictionary<string, T?>();
        foreach (var id in ids)
        {
            dictionary[id] = FindById(id);
        }
        return Task.FromResult<IDictionary<string, T?>>(dictionary);
    }

    public T First(Expression<Func<T, bool>> expression)
    {
        return Items.First(expression.Compile());
    }

    public Task<T> FirstAsync()
    {
        return Task.FromResult(Items.First());
    }

    public Task<T> FirstAsync(Expression<Func<T, bool>> expression)
    {
        return Task.FromResult(Items.First(expression.Compile()));
    }

    public T? FirstOrDefault(Expression<Func<T, bool>> expression)
    {
        return Items.FirstOrDefault(expression.Compile());
    }

    public Task<T?> FirstOrDefaultAsync()
    {
        return Task.FromResult(Items.FirstOrDefault());
    }

    public Task<T?> FirstOrDefaultAsync(Expression<Func<T, bool>> expression)
    {
        return Task.FromResult(Items.FirstOrDefault(expression.Compile()));
    }

    public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
    {
        throw new NotImplementedException();
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Items.GetEnumerator();
    }

    public string Insert(T item)
    {
        Items.Add(item);
        return item.ToString();
    }

    public string Insert(T item, TimeSpan timeSpan)
    {
        return Insert(item);
    }

    public string? Insert(T item, WhenKey when, TimeSpan? timeSpan = null)
    {
        return Insert(item);
    }

    public Task<string> InsertAsync(T item)
    {
        return Task.FromResult(Insert(item));
    }

    public Task<string> InsertAsync(T item, TimeSpan timeSpan)
    {
        return Task.FromResult(Insert(item));
    }

    public Task<string?> InsertAsync(T item, WhenKey when, TimeSpan? timeSpan = null)
    {
        throw new NotImplementedException();
    }

    public Task<List<string>> InsertAsync(IEnumerable<T> items)
    {
        throw new NotImplementedException();
    }

    public Task<List<string>> InsertAsync(IEnumerable<T> items, TimeSpan timeSpan)
    {
        return InsertAsync(items);
    }

    public Task<List<string?>> InsertAsync(IEnumerable<T> items, WhenKey when, TimeSpan? timeSpan = null)
    {
        return InsertAsync(items);
    }

    public void Save()
    {
        // No implementation needed
    }

    public ValueTask SaveAsync()
    {
        return new ValueTask(Task.CompletedTask);
    }

    public T Single(Expression<Func<T, bool>> expression)
    {
        return Items.Single(expression.Compile());
    }

    public Task<T> SingleAsync()
    {
        return Task.FromResult(Items.Single());
    }

    public Task<T> SingleAsync(Expression<Func<T, bool>> expression)
    {
        return Task.FromResult(Items.Single(expression.Compile()));
    }

    public T? SingleOrDefault(Expression<Func<T, bool>> expression)
    {
        return Items.SingleOrDefault(expression.Compile());
    }

    public Task<T?> SingleOrDefaultAsync()
    {
        return Task.FromResult(Items.SingleOrDefault());
    }

    public Task<T?> SingleOrDefaultAsync(Expression<Func<T, bool>> expression)
    {
        return Task.FromResult(Items.SingleOrDefault(expression.Compile()));
    }

    public void Update(T item)
    {
        // No implementation needed
    }

    public Task UpdateAsync(T item)
    {
        return Task.CompletedTask;
    }

    public ValueTask UpdateAsync(IEnumerable<T> items)
    {
        return new ValueTask(Task.CompletedTask);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public Task<IList<T>> ToListAsync()
    {
        throw new NotImplementedException();
    }

    public void Update(T item, TimeSpan ttl)
    {
        throw new NotImplementedException();
    }

    public Task UpdateAsync(T item, TimeSpan ttl)
    {
        throw new NotImplementedException();
    }

    public ValueTask UpdateAsync(IEnumerable<T> items, TimeSpan ttl)
    {
        throw new NotImplementedException();
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant