11using FakeItEasy ;
22using Microsoft . EntityFrameworkCore ;
3+ using MockQueryable . Core ;
34using MockQueryable . EntityFrameworkCore ;
45using System . Collections . Generic ;
56using System . Linq ;
7+ using System . Linq . Expressions ;
68using System . Threading ;
79using System . Threading . Tasks ;
810
911namespace MockQueryable . FakeItEasy
1012{
11- public static class FakeItEasyExtensions
13+ public static class FakeItEasyExtensions
14+ {
15+ public static DbSet < TEntity > BuildMockDbSet < TEntity , TExpressionVisitor > ( this IEnumerable < TEntity > data )
16+ where TEntity : class
17+ where TExpressionVisitor : ExpressionVisitor , new ( )
18+ => data . BuildMock < TEntity , TExpressionVisitor > ( ) . BuildMockDbSet ( ) ;
19+
20+ public static DbSet < TEntity > BuildMockDbSet < TEntity > ( this IEnumerable < TEntity > data )
21+ where TEntity : class
22+ => data . BuildMock ( ) . BuildMockDbSet ( ) ;
23+
24+ /// <summary>
25+ /// This method allows you to create a mock DbSet for testing purposes.
26+ /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet
27+ /// with custom expression handling, such as for testing LINQ queries or database operations.
28+ /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements
29+ /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration
30+ /// and LINQ query capabilities.
31+ /// </summary>
32+ /// <typeparam name="TEntity">
33+ /// The type of the entity that the DbSet will represent.
34+ /// </typeparam>
35+ public static DbSet < TEntity > BuildMockDbSet < TEntity > ( this IQueryable < TEntity > data ) where TEntity : class
1236 {
13- public static DbSet < TEntity > BuildMockDbSet < TEntity > ( this IEnumerable < TEntity > data ) where TEntity : class => data . BuildMock ( ) . BuildMockDbSet ( ) ;
37+ return BuildMockDbSet < TEntity , TestExpressionVisitor > ( data ) ;
38+ }
1439
15- public static DbSet < TEntity > BuildMockDbSet < TEntity > ( this IQueryable < TEntity > data ) where TEntity : class
16- {
17- var mock = A . Fake < DbSet < TEntity > > ( d => d . Implements < IAsyncEnumerable < TEntity > > ( ) . Implements < IQueryable < TEntity > > ( ) ) ;
18- var enumerable = new TestAsyncEnumerableEfCore < TEntity > ( data ) ;
19- mock . ConfigureQueryableCalls ( enumerable , data ) ;
20- mock . ConfigureAsyncEnumerableCalls ( enumerable ) ;
21- mock . ConfigureDbSetCalls ( data ) ;
22- if ( mock is IAsyncEnumerable < TEntity > asyncEnumerable )
23- {
24- A . CallTo ( ( ) => asyncEnumerable . GetAsyncEnumerator ( A < CancellationToken > . Ignored ) ) . ReturnsLazily ( ( ) => enumerable . GetAsyncEnumerator ( ) ) ;
25- }
26- return mock ;
27- }
40+ /// <summary>
41+ /// See <see cref="BuildMockDbSet{TEntity}"/>.
42+ /// </summary>
43+ /// <typeparam name="TEntity">
44+ /// The type of the entity that the DbSet will represent.
45+ /// </typeparam>
46+ /// <typeparam name="TExpressionVisitor">
47+ /// The type of the expression visitor that will be used to process LINQ expressions.
48+ /// Can be used to mock EF Core specific expression handling, such as for ILike expressions.
49+ /// </typeparam>
50+ public static DbSet < TEntity > BuildMockDbSet < TEntity , TExpressionVisitor > ( this IQueryable < TEntity > data )
51+ where TEntity : class
52+ where TExpressionVisitor : ExpressionVisitor , new ( )
53+ {
54+ var mock = A . Fake < DbSet < TEntity > > ( d => d . Implements < IAsyncEnumerable < TEntity > > ( ) . Implements < IQueryable < TEntity > > ( ) ) ;
55+ var enumerable = new TestAsyncEnumerableEfCore < TEntity , TExpressionVisitor > ( data ) ;
56+ mock . ConfigureQueryableCalls ( enumerable , data ) ;
57+ mock . ConfigureAsyncEnumerableCalls ( enumerable ) ;
58+ mock . ConfigureDbSetCalls ( data ) ;
2859
60+ if ( mock is IAsyncEnumerable < TEntity > asyncEnumerable )
61+ {
62+ A . CallTo ( ( ) => asyncEnumerable . GetAsyncEnumerator ( A < CancellationToken > . Ignored ) ) . ReturnsLazily ( ( ) => enumerable . GetAsyncEnumerator ( ) ) ;
63+ }
2964
30- private static void ConfigureQueryableCalls < TEntity > (
31- this IQueryable < TEntity > mock ,
32- IQueryProvider queryProvider ,
33- IQueryable < TEntity > data ) where TEntity : class
34- {
35- A . CallTo ( ( ) => mock . Provider ) . Returns ( queryProvider ) ;
36- A . CallTo ( ( ) => mock . Expression ) . Returns ( data ? . Expression ) ;
37- A . CallTo ( ( ) => mock . ElementType ) . Returns ( data ? . ElementType ) ;
38- A . CallTo ( ( ) => mock . GetEnumerator ( ) ) . ReturnsLazily ( ( ) => data ? . GetEnumerator ( ) ) ;
39- }
65+ return mock ;
66+ }
4067
41- private static void ConfigureAsyncEnumerableCalls < TEntity > (
42- this DbSet < TEntity > mock ,
43- IAsyncEnumerable < TEntity > enumerable ) where TEntity : class
44- {
45- A . CallTo ( ( ) => mock . GetAsyncEnumerator ( A < CancellationToken > . Ignored ) )
46- . Returns ( enumerable . GetAsyncEnumerator ( ) ) ;
47-
48- }
68+ private static void ConfigureQueryableCalls < TEntity > (
69+ this IQueryable < TEntity > mock ,
70+ IQueryProvider queryProvider ,
71+ IQueryable < TEntity > data ) where TEntity : class
72+ {
73+ A . CallTo ( ( ) => mock . Provider ) . Returns ( queryProvider ) ;
74+ A . CallTo ( ( ) => mock . Expression ) . Returns ( data ? . Expression ) ;
75+ A . CallTo ( ( ) => mock . ElementType ) . Returns ( data ? . ElementType ) ;
76+ A . CallTo ( ( ) => mock . GetEnumerator ( ) ) . ReturnsLazily ( ( ) => data ? . GetEnumerator ( ) ) ;
77+ }
4978
50- private static void ConfigureDbSetCalls < TEntity > ( this DbSet < TEntity > mock , IQueryable < TEntity > data )
51- where TEntity : class
52- {
53- A . CallTo ( ( ) => mock . AsQueryable ( ) ) . Returns ( data ) ;
54- A . CallTo ( ( ) => mock . AsAsyncEnumerable ( ) ) . ReturnsLazily ( args => CreateAsyncMock ( data ) ) ;
55- }
79+ private static void ConfigureAsyncEnumerableCalls < TEntity > (
80+ this DbSet < TEntity > mock ,
81+ IAsyncEnumerable < TEntity > enumerable ) where TEntity : class
82+ {
83+ A . CallTo ( ( ) => mock . GetAsyncEnumerator ( A < CancellationToken > . Ignored ) )
84+ . Returns ( enumerable . GetAsyncEnumerator ( ) ) ;
85+ }
86+
87+ private static void ConfigureDbSetCalls < TEntity > ( this DbSet < TEntity > mock , IQueryable < TEntity > data )
88+ where TEntity : class
89+ {
90+ A . CallTo ( ( ) => mock . AsQueryable ( ) ) . Returns ( data ) ;
91+ A . CallTo ( ( ) => mock . AsAsyncEnumerable ( ) ) . ReturnsLazily ( args => CreateAsyncMock ( data ) ) ;
92+ }
5693
57- private static async IAsyncEnumerable < TEntity > CreateAsyncMock < TEntity > ( IEnumerable < TEntity > data )
58- where TEntity : class
59- {
60- foreach ( var entity in data )
61- {
62- yield return entity ;
63- }
94+ private static async IAsyncEnumerable < TEntity > CreateAsyncMock < TEntity > ( IEnumerable < TEntity > data )
95+ where TEntity : class
96+ {
97+ foreach ( var entity in data )
98+ {
99+ yield return entity ;
100+ }
64101
65- await Task . CompletedTask ;
66- }
102+ await Task . CompletedTask ;
67103 }
104+ }
68105}
0 commit comments