improve DbSetMock.

добавлена поддержка асинхронных методов в DbSetMock.
AddDbSetMock также мокает свойство соответствующего типа.
This commit is contained in:
ngfrolov 2022-11-22 17:26:06 +05:00
parent 9b06438935
commit 0ea49dd72f

View File

@ -2,15 +2,18 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Moq; using Moq;
using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudWebApi.Tests namespace AsbCloudWebApi.Tests
{ {
internal static class TestHelpter internal static class TestHelpter
{ {
// Попробовать когда-нибудь https://github.com/MichalJankowskii/Moq.EntityFrameworkCore
public static IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions()); public static IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions());
public static AsbCloudDbContext MakeRealTestContext() public static AsbCloudDbContext MakeRealTestContext()
@ -30,22 +33,82 @@ namespace AsbCloudWebApi.Tests
contextMock.Setup(o => o.Set<T>()) contextMock.Setup(o => o.Set<T>())
.Returns(() => dbSetMock.Object); .Returns(() => dbSetMock.Object);
var dbSetProperty = typeof(IAsbCloudDbContext)
.GetProperties()
.FirstOrDefault(p => p.PropertyType.IsPublic && p.PropertyType == typeof(DbSet<T>));
if (dbSetProperty is not null)
{
// https://learn.microsoft.com/ru-ru/dotnet/api/system.linq.expressions.expression?view=net-7.0
var objParameterExpr = Expression.Parameter(typeof(IAsbCloudDbContext), "instance");
var propertyExpr = Expression.Property(objParameterExpr, dbSetProperty);
var expression = Expression.Lambda<Func<IAsbCloudDbContext, DbSet<T>>>(propertyExpr, objParameterExpr);
contextMock.SetupGet(expression).Returns(dbSetMock.Object);
}
return contextMock; return contextMock;
} }
public static Mock<DbSet<T>> MakeDbSetMock<T>() public static Mock<DbSet<T>> MakeDbSetMock<T>()
where T : class where T : class
=> MakeDbSetMock(new List<T>());
class DummyAsyncQueriable<T> : IQueryable<T>, IAsyncEnumerable<T>
{ {
var dbSetData = new List<T>(); private readonly IQueryable<T> queriable;
return MakeDbSetMock(dbSetData);
public Type ElementType => queriable.ElementType;
public Expression Expression => queriable.Expression;
public IQueryProvider Provider => queriable.Provider;
class QueriableAsyncEminaretor<T2> : IAsyncEnumerator<T2>
{
private readonly IEnumerator<T2> syncEnumerator;
public QueriableAsyncEminaretor(IEnumerator<T2> syncEnumerator)
{
this.syncEnumerator = syncEnumerator;
}
public T2 Current => syncEnumerator.Current;
public ValueTask DisposeAsync()
{
syncEnumerator.Dispose();
return ValueTask.CompletedTask;
}
public ValueTask<bool> MoveNextAsync()
{
var result = syncEnumerator.MoveNext();
return ValueTask.FromResult(result);
}
}
public DummyAsyncQueriable(IEnumerable<T> dbSetData)
{
queriable = dbSetData.ToList().AsQueryable();
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
var enumerator = this.AsEnumerable().GetEnumerator();
return new QueriableAsyncEminaretor<T>(enumerator);
}
public IEnumerator<T> GetEnumerator()
=> queriable.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> queriable.GetEnumerator();
} }
public static Mock<DbSet<T>> MakeDbSetMock<T>(IEnumerable<T> dbSetData) public static Mock<DbSet<T>> MakeDbSetMock<T>(IEnumerable<T> dbSetData)
where T : class where T : class
{ {
var dbSetDataQueriable = dbSetData var dbSetDataQueriable = new DummyAsyncQueriable<T>(dbSetData);
.ToList()
.AsQueryable();
Mock<DbSet<T>> dbSetMock = new(); Mock<DbSet<T>> dbSetMock = new();
dbSetMock.As<IQueryable<T>>().Setup(o => o.Provider).Returns(() => dbSetDataQueriable.Provider); dbSetMock.As<IQueryable<T>>().Setup(o => o.Provider).Returns(() => dbSetDataQueriable.Provider);
@ -53,6 +116,10 @@ namespace AsbCloudWebApi.Tests
dbSetMock.As<IQueryable<T>>().Setup(o => o.ElementType).Returns(() => dbSetDataQueriable.ElementType); dbSetMock.As<IQueryable<T>>().Setup(o => o.ElementType).Returns(() => dbSetDataQueriable.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(o => o.GetEnumerator()).Returns(() => dbSetDataQueriable.GetEnumerator()); dbSetMock.As<IQueryable<T>>().Setup(o => o.GetEnumerator()).Returns(() => dbSetDataQueriable.GetEnumerator());
dbSetMock.As<IAsyncEnumerable<T>>()
.Setup(o => o.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
.Returns(() => dbSetDataQueriable.GetAsyncEnumerator());
return dbSetMock; return dbSetMock;
} }
} }