redis-om-dotnet
redis-om-dotnet copied to clipboard
Making IRedisCollection<T> more unit test friendly
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.
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();
}
}