Skip to content

Commit a89730c

Browse files
committed
Corrected SampleLikeExpressionVisitor to support Like and ILike. Added additional tests for Like. Updated README
1 parent 1455ff7 commit a89730c

File tree

15 files changed

+1068
-828
lines changed

15 files changed

+1068
-828
lines changed

.github/workflows/dotnetcore.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- name: Setup .NET Core
1313
uses: actions/setup-dotnet@v1
1414
with:
15-
dotnet-version: '6.0.x'
15+
dotnet-version: '8.0.x'
1616

1717
- name: Build with dotnet
1818
run: dotnet build src/MockQueryable/*.sln --configuration Release

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ var userRepository = new TestDbSetRepository(mock.Object);
9191
var user = await ((DbSet<UserEntity>) userRepository.GetQueryable()).FindAsync(userId);
9292
```
9393

94+
You can also add your custom expression visitor with custom logic:
95+
96+
```C#
97+
98+
var users = new List<UserEntity>
99+
{
100+
new UserEntity{Id = userId,LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")},
101+
//etc.
102+
};
103+
104+
//Bould mock with custom SampleLikeExpressionVisitor, that emulates EF.Functions.Like
105+
var mockDbSet = users.AsQueryable().BuildMockDbSet<UserEntity, SampleLikeExpressionVisitor>();
106+
var userRepository = new TestDbSetRepository(mockDbSet.Object);
107+
108+
```
109+
94110
Check out the [sample project](https://github.com/romantitov/MockQueryable/tree/master/src/MockQueryable/MockQueryable.Sample)
95111

96112
### Where can I get it?

src/MockQueryable/MockQueryable.Core/MockQueryable.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netstandard2.1</TargetFramework>
4+
<TargetFramework>net8</TargetFramework>
55
<PackageId>MockQueryable.Core</PackageId>
66
<Authors>Roman Titov</Authors>
77
<Description>

src/MockQueryable/MockQueryable.Core/TestQueryProvider.cs

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,79 +6,81 @@
66

77
namespace MockQueryable.Core
88
{
9-
public abstract class TestQueryProvider<T, TExpressionVisitor> : IOrderedQueryable<T>, IQueryProvider
10-
where TExpressionVisitor : ExpressionVisitor, new()
11-
{
12-
private IEnumerable<T> _enumerable;
9+
public abstract class TestQueryProvider<T, TExpressionVisitor> : IOrderedQueryable<T>, IQueryProvider
10+
where TExpressionVisitor : ExpressionVisitor, new()
11+
{
12+
private IEnumerable<T> _enumerable;
1313

14-
protected TestQueryProvider(Expression expression)
15-
{
16-
Expression = expression;
17-
}
14+
protected TestQueryProvider(Expression expression)
15+
{
16+
Expression = expression;
17+
}
1818

19-
protected TestQueryProvider(IEnumerable<T> enumerable)
20-
{
21-
_enumerable = enumerable;
22-
Expression = enumerable.AsQueryable().Expression;
23-
}
19+
protected TestQueryProvider(IEnumerable<T> enumerable)
20+
{
21+
_enumerable = enumerable;
22+
Expression = enumerable.AsQueryable().Expression;
23+
}
2424

25-
public IQueryable CreateQuery(Expression expression)
26-
{
27-
if (expression is MethodCallExpression m)
28-
{
29-
var resultType = m.Method.ReturnType; // it should be IQueryable<T>
30-
var tElement = resultType.GetGenericArguments().First();
31-
return (IQueryable) CreateInstance(tElement, expression);
32-
}
25+
public IQueryable CreateQuery(Expression expression)
26+
{
27+
if (expression is MethodCallExpression m)
28+
{
29+
var resultType = m.Method.ReturnType; // it should be IQueryable<T>
30+
var tElement = resultType.GetGenericArguments().First();
31+
return (IQueryable)CreateInstance(tElement, expression);
32+
}
3333

34-
return CreateQuery<T>(expression);
35-
}
34+
return CreateQuery<T>(expression);
35+
}
3636

37-
public IQueryable<TEntity> CreateQuery<TEntity>(Expression expression)
38-
{
39-
return (IQueryable<TEntity>) CreateInstance(typeof(TEntity), expression);
40-
}
37+
public IQueryable<TEntity> CreateQuery<TEntity>(Expression expression)
38+
{
39+
return (IQueryable<TEntity>)CreateInstance(typeof(TEntity), expression);
40+
}
4141

42-
private object CreateInstance(Type tElement, Expression expression)
43-
{
44-
var queryType = GetType().GetGenericTypeDefinition().MakeGenericType(tElement, typeof(TExpressionVisitor));
45-
return Activator.CreateInstance(queryType, expression);
46-
}
42+
private object CreateInstance(Type tElement, Expression expression)
43+
{
44+
var queryType = GetType().GetGenericTypeDefinition().MakeGenericType(tElement, typeof(TExpressionVisitor));
45+
return Activator.CreateInstance(queryType, expression);
46+
}
4747

48-
public object Execute(Expression expression)
49-
{
50-
return CompileExpressionItem<object>(expression);
51-
}
48+
public object Execute(Expression expression)
49+
{
50+
return CompileExpressionItem<object>(expression);
51+
}
5252

53-
public TResult Execute<TResult>(Expression expression)
54-
{
55-
return CompileExpressionItem<TResult>(expression);
56-
}
53+
public TResult Execute<TResult>(Expression expression)
54+
{
55+
return CompileExpressionItem<TResult>(expression);
56+
}
5757

58-
IEnumerator<T> IEnumerable<T>.GetEnumerator()
59-
{
60-
if (_enumerable == null) _enumerable = CompileExpressionItem<IEnumerable<T>>(Expression);
61-
return _enumerable.GetEnumerator();
62-
}
58+
IEnumerator<T> IEnumerable<T>.GetEnumerator()
59+
{
60+
if (_enumerable == null) _enumerable = CompileExpressionItem<IEnumerable<T>>(Expression);
61+
return _enumerable.GetEnumerator();
62+
}
6363

64-
IEnumerator IEnumerable.GetEnumerator()
65-
{
66-
if (_enumerable == null) _enumerable = CompileExpressionItem<IEnumerable<T>>(Expression);
67-
return _enumerable.GetEnumerator();
68-
}
64+
IEnumerator IEnumerable.GetEnumerator()
65+
{
66+
if (_enumerable == null) _enumerable = CompileExpressionItem<IEnumerable<T>>(Expression);
67+
return _enumerable.GetEnumerator();
68+
}
6969

70-
public Type ElementType => typeof(T);
70+
public Type ElementType => typeof(T);
7171

72-
public Expression Expression { get; }
72+
public Expression Expression { get; }
7373

74-
public IQueryProvider Provider => this;
74+
public IQueryProvider Provider => this;
7575

76-
private static TResult CompileExpressionItem<TResult>(Expression expression)
77-
{
78-
var visitor = new TExpressionVisitor();
79-
var body = visitor.Visit(expression);
80-
var f = Expression.Lambda<Func<TResult>>(body ?? throw new InvalidOperationException($"{nameof(body)} is null"), (IEnumerable<ParameterExpression>) null);
81-
return f.Compile()();
82-
}
83-
}
76+
private static TResult CompileExpressionItem<TResult>(Expression expression)
77+
{
78+
var visitor = new TExpressionVisitor();
79+
var body = visitor.Visit(expression);
80+
var f = Expression.Lambda<Func<TResult>>(
81+
body ?? throw new InvalidOperationException($"{nameof(body)} is null"),
82+
(IEnumerable<ParameterExpression>)null);
83+
return f.Compile()();
84+
}
85+
}
8486
}

src/MockQueryable/MockQueryable.FakeItEasy/FakeItEasyExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ public static DbSet<TEntity> BuildMockDbSet<TEntity>(this IQueryable<TEntity> da
3838
}
3939

4040
/// <summary>
41-
/// See <see cref="BuildMockDbSet{TEntity}"/>.
41+
/// This method allows you to create a mock DbSet for testing purposes.
42+
/// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet
43+
/// with custom expression handling, such as for testing LINQ queries or database operations.
44+
/// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements
45+
/// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration
46+
/// and LINQ query capabilities.
4247
/// </summary>
4348
/// <typeparam name="TEntity">
4449
/// The type of the entity that the DbSet will represent.

src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ public static Mock<DbSet<TEntity>> BuildMockDbSet<TEntity>(this IQueryable<TEnti
3939
}
4040

4141
/// <summary>
42-
/// See <see cref="BuildMockDbSet{TEntity}"/>.
42+
/// This method allows you to create a mock DbSet for testing purposes.
43+
/// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet
44+
/// with custom expression handling, such as for testing LINQ queries or database operations.
45+
/// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements
46+
/// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration
47+
/// and LINQ query capabilities.
4348
/// </summary>
4449
/// <typeparam name="TEntity">
4550
/// The type of the entity that the DbSet will represent.

src/MockQueryable/MockQueryable.NSubstitute/NSubstituteExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ public static DbSet<TEntity> BuildMockDbSet<TEntity>(this IQueryable<TEntity> da
3636
}
3737

3838
/// <summary>
39-
/// See <see cref="BuildMockDbSet{TEntity}"/>.
39+
/// This method allows you to create a mock DbSet for testing purposes.
40+
/// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet
41+
/// with custom expression handling, such as for testing LINQ queries or database operations.
42+
/// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements
43+
/// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration
44+
/// and LINQ query capabilities.
4045
/// </summary>
4146
/// <typeparam name="TEntity">
4247
/// The type of the entity that the DbSet will represent.

src/MockQueryable/MockQueryable.Sample/MockQueryable.Sample.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
<TargetFramework>net8</TargetFramework>
55
</PropertyGroup>
66

7+
<ItemGroup>
8+
<None Include="SampleLikeExpressionVisitor.cs" />
9+
</ItemGroup>
10+
711
<ItemGroup>
812
<PackageReference Include="AutoMapper" Version="15.0.1" />
913
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />

0 commit comments

Comments
 (0)