diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index bd49b40..fceb363 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -12,7 +12,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Build with dotnet run: dotnet build src/MockQueryable/*.sln --configuration Release diff --git a/README.md b/README.md index 490c408..973fd05 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Do you prefer *DbSet*? ```csharp //2 - build mock by extension -var mock = users.AsQueryable().BuildMockDbSet(); +var mock = users.BuildMockDbSet(); //3 - setup DbSet for Moq var userRepository = new TestDbSetRepository(mock.Object); @@ -77,7 +77,7 @@ var users = new List new UserEntity{Id = userId,LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")}, //etc. }; -var mock = users.AsQueryable().BuildMockDbSet(); +var mock = users.BuildMockDbSet(); //Aditional setup for FindAsync mock.Setup(x => x.FindAsync(userId)).ReturnsAsync((object[] ids) => @@ -91,6 +91,22 @@ var userRepository = new TestDbSetRepository(mock.Object); var user = await ((DbSet) userRepository.GetQueryable()).FindAsync(userId); ``` +You can also add your custom expression visitor with custom logic: + +```C# + +var users = new List +{ + new UserEntity{Id = userId,LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")}, + //etc. +}; + +//Bould mock with custom SampleLikeExpressionVisitor, that emulates EF.Functions.Like +var mockDbSet = users.BuildMockDbSet(); +var userRepository = new TestDbSetRepository(mockDbSet.Object); + +``` + Check out the [sample project](https://github.com/romantitov/MockQueryable/tree/master/src/MockQueryable/MockQueryable.Sample) ### Where can I get it? diff --git a/src/MockQueryable/MockQueryable.Core/MockQueryable.Core.csproj b/src/MockQueryable/MockQueryable.Core/MockQueryable.Core.csproj index 55b5ba7..2ce3c05 100644 --- a/src/MockQueryable/MockQueryable.Core/MockQueryable.Core.csproj +++ b/src/MockQueryable/MockQueryable.Core/MockQueryable.Core.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net8 MockQueryable.Core Roman Titov @@ -14,11 +14,14 @@ Mock EntityFrameworkCore Queryable mock EF UnitTests EntityFrameworkCore true - #80 Altered namespace for extension method to revert a breaking change - Thanks @StevePy + #81 Add support to ExecuteDelete and ExecuteUpdate - Thanks @lazaro-ansaldi and @Catlandor + #82 Update versions of Moq, NSubstitute and FakeItEasy to newer versions without known vulnerabilities - Thanks @Catlandor + #73 Supporting EF.Functions.Like and/or prossibility to provide cusotm ExpressionVisitor - Thanks @Catlandor + #66 Not suported with EF7: ExecuteDeleteAsync and ExecuteUpdateAsync - Thanks @Catlandor - 7.0.3 - 7.0.0.3 - 7.0.0.3 + 8.0.0 + 8.0.0.0 + 8.0.0.0 LICENSE README.md diff --git a/src/MockQueryable/MockQueryable.Core/TestQueryProvider.cs b/src/MockQueryable/MockQueryable.Core/TestQueryProvider.cs index 264b051..6d003d7 100644 --- a/src/MockQueryable/MockQueryable.Core/TestQueryProvider.cs +++ b/src/MockQueryable/MockQueryable.Core/TestQueryProvider.cs @@ -4,80 +4,82 @@ using System.Linq; using System.Linq.Expressions; -namespace MockQueryable.Core +namespace MockQueryable.Core; + +public abstract class TestQueryProvider : IOrderedQueryable, IQueryProvider + where TExpressionVisitor : ExpressionVisitor, new() { - public abstract class TestQueryProvider : IOrderedQueryable, IQueryProvider - { - private IEnumerable _enumerable; + private IEnumerable _enumerable; + protected TestQueryProvider(Expression expression) - { - Expression = expression; - } + { + Expression = expression; + } protected TestQueryProvider(IEnumerable enumerable) - { - _enumerable = enumerable; - Expression = enumerable.AsQueryable().Expression; - } - - public IQueryable CreateQuery(Expression expression) - { - if (expression is MethodCallExpression m) - { - var resultType = m.Method.ReturnType; // it should be IQueryable - var tElement = resultType.GetGenericArguments().First(); - return (IQueryable) CreateInstance(tElement, expression); - } - - return CreateQuery(expression); - } - - public IQueryable CreateQuery(Expression expression) - { - return (IQueryable) CreateInstance(typeof(TEntity), expression); + { + _enumerable = enumerable; + Expression = enumerable.AsQueryable().Expression; + + } + + public IQueryable CreateQuery(Expression expression) + { + if (expression is MethodCallExpression m) + { + var resultType = m.Method.ReturnType; // it should be IQueryable + var tElement = resultType.GetGenericArguments().First(); + return (IQueryable)CreateInstance(tElement, expression); + } + + return CreateQuery(expression); + } + + public IQueryable CreateQuery(Expression expression) + { + return (IQueryable)CreateInstance(typeof(TEntity), expression); } - private object CreateInstance(Type tElement, Expression expression) + protected abstract object CreateInstance(Type tElement, Expression expression); + + + public object Execute(Expression expression) { - var queryType = GetType().GetGenericTypeDefinition().MakeGenericType(tElement); - return Activator.CreateInstance(queryType, expression); - } - - public object Execute(Expression expression) - { - return CompileExpressionItem(expression); - } - - public TResult Execute(Expression expression) - { - return CompileExpressionItem(expression); - } - - IEnumerator IEnumerable.GetEnumerator() - { - if (_enumerable == null) _enumerable = CompileExpressionItem>(Expression); - return _enumerable.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - if (_enumerable == null) _enumerable = CompileExpressionItem>(Expression); - return _enumerable.GetEnumerator(); - } - - public Type ElementType => typeof(T); - - public Expression Expression { get; } - - public IQueryProvider Provider => this; - - private static TResult CompileExpressionItem(Expression expression) - { - var visitor = new TestExpressionVisitor(); - var body = visitor.Visit(expression); - var f = Expression.Lambda>(body ?? throw new InvalidOperationException($"{nameof(body)} is null"), (IEnumerable) null); - return f.Compile()(); - } - } + return CompileExpressionItem(expression); + } + + public virtual TResult Execute(Expression expression) + { + + return CompileExpressionItem(expression); + } + + IEnumerator IEnumerable.GetEnumerator() + { + _enumerable ??= CompileExpressionItem>(Expression); + return _enumerable.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + _enumerable ??= CompileExpressionItem>(Expression); + return _enumerable.GetEnumerator(); + } + + public Type ElementType => typeof(T); + + public Expression Expression { get; } + + public IQueryProvider Provider => this; + + private static TResult CompileExpressionItem(Expression expression) + { + var visitor = new TExpressionVisitor(); + var body = visitor.Visit(expression); + var f = Expression.Lambda>( + body ?? throw new InvalidOperationException($"{nameof(body)} is null"), + (IEnumerable)null); + return f.Compile()(); + } } \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryable.EntityFrameworkCore.csproj b/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryable.EntityFrameworkCore.csproj index 88963b3..9d3b280 100644 --- a/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryable.EntityFrameworkCore.csproj +++ b/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryable.EntityFrameworkCore.csproj @@ -1,7 +1,7 @@ - net6 + net8 MockQueryable.EntityFrameworkCore Roman Titov @@ -15,11 +15,14 @@ Mock EntityFrameworkCore Queryable mock EF UnitTests EntityFrameworkCore true - #80 Altered namespace for extension method to revert a breaking change - Thanks @StevePy + #81 Add support to ExecuteDelete and ExecuteUpdate - Thanks @lazaro-ansaldi and @Catlandor + #82 Update versions of Moq, NSubstitute and FakeItEasy to newer versions without known vulnerabilities - Thanks @Catlandor + #73 Supporting EF.Functions.Like and/or prossibility to provide cusotm ExpressionVisitor - Thanks @Catlandor + #66 Not suported with EF7: ExecuteDeleteAsync and ExecuteUpdateAsync - Thanks @Catlandor - 7.0.3 - 7.0.0.3 - 7.0.0.3 + 8.0.0 + 8.0.0.0 + 8.0.0.0 LICENSE README.md @@ -45,7 +48,7 @@ - + diff --git a/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryableExtensions.cs b/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryableExtensions.cs index c94b1c8..9280f77 100644 --- a/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryableExtensions.cs +++ b/src/MockQueryable/MockQueryable.EntityFrameworkCore/MockQueryableExtensions.cs @@ -1,6 +1,8 @@ -using MockQueryable.EntityFrameworkCore; +using MockQueryable.Core; +using MockQueryable.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; // Moving MockQueryableExtensions BuildMock into the MockQueryable.EntityFrameworkCore // namespace had breaking changes with earlier extensions added to MockQueryable.Moq @@ -9,11 +11,19 @@ // is dependent on the EF Core AsyncEnumerable. namespace MockQueryable { - public static class MockQueryableExtensions + public static class MockQueryableExtensions + { + public static IQueryable BuildMock(this ICollection data) + where TEntity : class { - public static IQueryable BuildMock(this IEnumerable data) where TEntity : class - { - return new TestAsyncEnumerableEfCore(data); - } + return new TestAsyncEnumerableEfCore(data, entity => data.Remove(entity)); } + + public static IQueryable BuildMock(this ICollection data) + where TEntity : class + where TExpressionVisitor : ExpressionVisitor, new() + { + return new TestAsyncEnumerableEfCore(data, entity => data.Remove(entity)); + } + } } diff --git a/src/MockQueryable/MockQueryable.EntityFrameworkCore/TestQueryProviderEfCore.cs b/src/MockQueryable/MockQueryable.EntityFrameworkCore/TestQueryProviderEfCore.cs index 9b637ba..8b37bce 100644 --- a/src/MockQueryable/MockQueryable.EntityFrameworkCore/TestQueryProviderEfCore.cs +++ b/src/MockQueryable/MockQueryable.EntityFrameworkCore/TestQueryProviderEfCore.cs @@ -1,40 +1,120 @@ -using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using MockQueryable.Core; +using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.Query; -using MockQueryable.Core; -namespace MockQueryable.EntityFrameworkCore +namespace MockQueryable.EntityFrameworkCore; + +public class TestAsyncEnumerableEfCore : TestQueryProvider, + IAsyncEnumerable, IAsyncQueryProvider + where TExpressionVisitor : ExpressionVisitor, new() { - public class TestAsyncEnumerableEfCore: TestQueryProvider, IAsyncEnumerable, IAsyncQueryProvider - { - public TestAsyncEnumerableEfCore(Expression expression) : base(expression) + private readonly Action _removeCallback; + + + public TestAsyncEnumerableEfCore(Expression expression, Action removeCallback) : base(expression) { + _removeCallback = removeCallback; } - public TestAsyncEnumerableEfCore(IEnumerable enumerable) : base(enumerable) + + public TestAsyncEnumerableEfCore(IEnumerable enumerable, Action removeCallback) : base(enumerable) { + _removeCallback = removeCallback; } - public TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken) + protected override object CreateInstance(Type tElement, Expression expression) { - var expectedResultType = typeof(TResult).GetGenericArguments()[0]; - var executionResult = typeof(IQueryProvider) - .GetMethods() - .First(method => method.Name == nameof(IQueryProvider.Execute) && method.IsGenericMethod) - .MakeGenericMethod(expectedResultType) - .Invoke(this, new object[] { expression }); - - return (TResult)typeof(Task).GetMethod(nameof(Task.FromResult)) - .MakeGenericMethod(expectedResultType) - .Invoke(null, new[] { executionResult }); + var queryType = GetType().GetGenericTypeDefinition().MakeGenericType(tElement, typeof(TExpressionVisitor)); + return typeof(T) == tElement + ? Activator.CreateInstance(queryType, expression, _removeCallback) + : Activator.CreateInstance(queryType, expression, null); + } + + public TResult ExecuteAsync(Expression expression, CancellationToken cancellationToken = default) + { + var expectedResultType = typeof(TResult).GetGenericArguments()[0]; + var executionResult = typeof(IQueryProvider) + .GetMethods() + .First(method => method.Name == nameof(IQueryProvider.Execute) && method.IsGenericMethod) + .MakeGenericMethod(expectedResultType) + .Invoke(this, [expression]); + + return (TResult)typeof(Task).GetMethod(nameof(Task.FromResult)) + .MakeGenericMethod(expectedResultType) + .Invoke(null, [executionResult]); + } + + public override TResult Execute(Expression expression) + { + // Intercept ExecuteDelete and ExecuteUpdate calls + if (expression is MethodCallExpression + { + Method.Name: nameof(EntityFrameworkQueryableExtensions.ExecuteUpdate) + or nameof(EntityFrameworkQueryableExtensions.ExecuteDelete) + } methodCall && + typeof(TResult) == typeof(int)) + { + var affectedItems = base.Execute>(Expression).ToList(); + + if (methodCall.Method.Name == nameof(EntityFrameworkQueryableExtensions.ExecuteUpdate)) + { + ApplyUpdateChangesToDbSet(affectedItems, methodCall); + } + + if (methodCall.Method.Name == nameof(EntityFrameworkQueryableExtensions.ExecuteDelete)) + { + foreach (var item in affectedItems) + { + + _removeCallback?.Invoke(item); + } + } + + // Return the count of affected items + return (TResult)(object)affectedItems.Count; + } + + // Fall back to default expression execution + return base.Execute(expression); } public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { - return new TestAsyncEnumerator(this.AsEnumerable().GetEnumerator()); + return new TestAsyncEnumerator(this.AsEnumerable().GetEnumerator()); + } + + private static void ApplyUpdateChangesToDbSet(IEnumerable affectedItems, + MethodCallExpression methodCallExpression) + { + // Extract the update lambda: opt => opt.SetProperty(...) + if ((methodCallExpression.Arguments[1] as UnaryExpression)?.Operand is not LambdaExpression updateLambda) + { + return; + } + + // The body may be a chain of MethodCallExpressions + var currentCall = updateLambda.Body as MethodCallExpression; + while (currentCall is { Method.Name: nameof(SetPropertyCalls.SetProperty) }) + { + var memberExpr = currentCall.Arguments[0] as LambdaExpression; + var valueExpr = currentCall.Arguments[1]; + + var propertyInfo = ((memberExpr.Body as MemberExpression)?.Member) as System.Reflection.PropertyInfo; + var value = Expression.Lambda(valueExpr).Compile().DynamicInvoke(); + + foreach (var item in affectedItems) + { + propertyInfo?.SetValue(item, value); + } + + // Move to the next chained call (if any) + currentCall = currentCall.Object as MethodCallExpression; + } } - } -} +} \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.FakeItEasy/FakeItEasyExtensions.cs b/src/MockQueryable/MockQueryable.FakeItEasy/FakeItEasyExtensions.cs index ee8c1b0..009ae10 100644 --- a/src/MockQueryable/MockQueryable.FakeItEasy/FakeItEasyExtensions.cs +++ b/src/MockQueryable/MockQueryable.FakeItEasy/FakeItEasyExtensions.cs @@ -1,68 +1,104 @@ using FakeItEasy; using Microsoft.EntityFrameworkCore; +using MockQueryable.Core; using MockQueryable.EntityFrameworkCore; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; namespace MockQueryable.FakeItEasy { - public static class FakeItEasyExtensions + public static class FakeItEasyExtensions + { + + /// + /// This method allows you to create a mock DbSet for testing purposes. + /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet + /// with custom expression handling, such as for testing LINQ queries or database operations. + /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements + /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration + /// and LINQ query capabilities. + /// + /// + /// The type of the entity that the DbSet will represent. + /// + public static DbSet BuildMockDbSet(this ICollection data) where TEntity : class { - public static DbSet BuildMockDbSet(this IEnumerable data) where TEntity : class => data.BuildMock().BuildMockDbSet(); + return BuildMockDbSet(data); + } - public static DbSet BuildMockDbSet(this IQueryable data) where TEntity : class - { - var mock = A.Fake>(d => d.Implements>().Implements>()); - var enumerable = new TestAsyncEnumerableEfCore(data); - mock.ConfigureQueryableCalls(enumerable, data); - mock.ConfigureAsyncEnumerableCalls(enumerable); - mock.ConfigureDbSetCalls(data); - if (mock is IAsyncEnumerable asyncEnumerable) - { - A.CallTo(() => asyncEnumerable.GetAsyncEnumerator(A.Ignored)).ReturnsLazily(() => enumerable.GetAsyncEnumerator()); - } - return mock; - } + /// + /// This method allows you to create a mock DbSet for testing purposes. + /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet + /// with custom expression handling, such as for testing LINQ queries or database operations. + /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements + /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration + /// and LINQ query capabilities. + /// + /// + /// The type of the entity that the DbSet will represent. + /// + /// + /// The type of the expression visitor that will be used to process LINQ expressions. + /// Can be used to mock EF Core specific expression handling, such as for ILike expressions. + /// + public static DbSet BuildMockDbSet(this ICollection data) + where TEntity : class + where TExpressionVisitor : ExpressionVisitor, new() + { + var mock = A.Fake>(d => d.Implements>().Implements>()); + var enumerable = new TestAsyncEnumerableEfCore(data, entity => data.Remove(entity)); + mock.ConfigureQueryableCalls(enumerable, data.AsQueryable()); + mock.ConfigureAsyncEnumerableCalls(enumerable); + mock.ConfigureDbSetCalls(data.AsQueryable()); + if (mock is IAsyncEnumerable asyncEnumerable) + { + A.CallTo(() => asyncEnumerable.GetAsyncEnumerator(A.Ignored)).ReturnsLazily(() => enumerable.GetAsyncEnumerator()); + } - private static void ConfigureQueryableCalls( - this IQueryable mock, - IQueryProvider queryProvider, - IQueryable data) where TEntity : class - { - A.CallTo(() => mock.Provider).Returns(queryProvider); - A.CallTo(() => mock.Expression).Returns(data?.Expression); - A.CallTo(() => mock.ElementType).Returns(data?.ElementType); - A.CallTo(() => mock.GetEnumerator()).ReturnsLazily(() => data?.GetEnumerator()); - } + return mock; + } - private static void ConfigureAsyncEnumerableCalls( - this DbSet mock, - IAsyncEnumerable enumerable) where TEntity : class - { - A.CallTo(() => mock.GetAsyncEnumerator(A.Ignored)) - .Returns(enumerable.GetAsyncEnumerator()); - - } + private static void ConfigureQueryableCalls( + this IQueryable mock, + IQueryProvider queryProvider, + IQueryable data) where TEntity : class + { + A.CallTo(() => mock.Provider).Returns(queryProvider); + A.CallTo(() => mock.Expression).Returns(data?.Expression); + A.CallTo(() => mock.ElementType).Returns(data?.ElementType); + A.CallTo(() => mock.GetEnumerator()).ReturnsLazily(() => data?.GetEnumerator()); + } - private static void ConfigureDbSetCalls(this DbSet mock, IQueryable data) - where TEntity : class - { - A.CallTo(() => mock.AsQueryable()).Returns(data); - A.CallTo(() => mock.AsAsyncEnumerable()).ReturnsLazily(args => CreateAsyncMock(data)); - } + private static void ConfigureAsyncEnumerableCalls( + this DbSet mock, + IAsyncEnumerable enumerable) where TEntity : class + { + A.CallTo(() => mock.GetAsyncEnumerator(A.Ignored)) + .Returns(enumerable.GetAsyncEnumerator()); + } + + private static void ConfigureDbSetCalls(this DbSet mock, IQueryable data) + where TEntity : class + { + A.CallTo(() => mock.AsQueryable()).Returns(data.AsQueryable()); + A.CallTo(() => mock.AsAsyncEnumerable()).ReturnsLazily(args => CreateAsyncMock(data)); + } + + private static async IAsyncEnumerable CreateAsyncMock( + this IEnumerable data) + where TEntity : class + { - private static async IAsyncEnumerable CreateAsyncMock(IEnumerable data) - where TEntity : class - { - foreach (var entity in data) - { - yield return entity; - } + foreach (var entity in data) + { + yield return entity; + } - await Task.CompletedTask; - } + await Task.CompletedTask; } + } } \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.FakeItEasy/MockQueryable.FakeItEasy.csproj b/src/MockQueryable/MockQueryable.FakeItEasy/MockQueryable.FakeItEasy.csproj index dbfedb2..59b27c9 100644 --- a/src/MockQueryable/MockQueryable.FakeItEasy/MockQueryable.FakeItEasy.csproj +++ b/src/MockQueryable/MockQueryable.FakeItEasy/MockQueryable.FakeItEasy.csproj @@ -1,7 +1,7 @@  - net6 + net8 MockQueryable.FakeItEasy Roman Titov @@ -14,11 +14,14 @@ Mock EntityFrameworkCore Queryable mock EF EFCore UnitTests FakeItEasy true - #80 Altered namespace for extension method to revert a breaking change - Thanks @StevePy + #81 Add support to ExecuteDelete and ExecuteUpdate - Thanks @lazaro-ansaldi and @Catlandor + #82 Update versions of Moq, NSubstitute and FakeItEasy to newer versions without known vulnerabilities - Thanks @Catlandor + #73 Supporting EF.Functions.Like and/or prossibility to provide cusotm ExpressionVisitor - Thanks @Catlandor + #66 Not suported with EF7: ExecuteDeleteAsync and ExecuteUpdateAsync - Thanks @Catlandor - 7.0.3 - 7.0.0.3 - 7.0.0.3 + 8.0.0 + 8.0.0.0 + 8.0.0.0 LICENSE README.md @@ -26,7 +29,7 @@ - + diff --git a/src/MockQueryable/MockQueryable.Moq/MockQueryable.Moq.csproj b/src/MockQueryable/MockQueryable.Moq/MockQueryable.Moq.csproj index c9c2fa6..3cb09b5 100644 --- a/src/MockQueryable/MockQueryable.Moq/MockQueryable.Moq.csproj +++ b/src/MockQueryable/MockQueryable.Moq/MockQueryable.Moq.csproj @@ -1,7 +1,7 @@  - net6 + net8 MockQueryable.Moq Roman Titov @@ -14,11 +14,14 @@ Mock EntityFrameworkCore Queryable mock EF EFCore UnitTests EntityFrameworkCore Moq true - #80 Altered namespace for extension method to revert a breaking change - Thanks @StevePy + #81 Add support to ExecuteDelete and ExecuteUpdate - Thanks @lazaro-ansaldi and @Catlandor + #82 Update versions of Moq, NSubstitute and FakeItEasy to newer versions without known vulnerabilities - Thanks @Catlandor + #73 Supporting EF.Functions.Like and/or prossibility to provide cusotm ExpressionVisitor - Thanks @Catlandor + #66 Not suported with EF7: ExecuteDeleteAsync and ExecuteUpdateAsync - Thanks @Catlandor - 7.0.3 - 7.0.0.3 - 7.0.0.3 + 8.0.0 + 8.0.0.0 + 8.0.0.0 LICENSE README.md @@ -26,7 +29,7 @@ - + diff --git a/src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs b/src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs index dafd6b0..23e655f 100644 --- a/src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs +++ b/src/MockQueryable/MockQueryable.Moq/MoqExtensions.cs @@ -1,68 +1,101 @@ -using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using MockQueryable.Core; +using MockQueryable.EntityFrameworkCore; +using Moq; +using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using MockQueryable.EntityFrameworkCore; -using Moq; namespace MockQueryable.Moq { public static class MoqExtensions { - public static Mock> BuildMockDbSet(this IEnumerable data) where TEntity : class => data.BuildMock().BuildMockDbSet(); + /// + /// This method allows you to create a mock DbSet for testing purposes. + /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet + /// with custom expression handling, such as for testing LINQ queries or database operations. + /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements + /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration + /// and LINQ query capabilities. + /// + /// + /// The type of the entity that the DbSet will represent. + /// + public static Mock> BuildMockDbSet(this ICollection data) where TEntity : class + { + return BuildMockDbSet(data); + } - public static Mock> BuildMockDbSet(this IQueryable data) where TEntity : class - { - var mock = new Mock>(); - var enumerable = new TestAsyncEnumerableEfCore(data); - mock.ConfigureAsyncEnumerableCalls(enumerable); - mock.As>().ConfigureQueryableCalls(enumerable, data); - mock.As>().Setup(x => x.GetAsyncEnumerator(It.IsAny())).Returns(() => enumerable.GetAsyncEnumerator()); - mock.Setup(m => m.AsQueryable()).Returns(enumerable); + /// + /// This method allows you to create a mock DbSet for testing purposes. + /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet + /// with custom expression handling, such as for testing LINQ queries or database operations. + /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements + /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration + /// and LINQ query capabilities. + /// + /// + /// The type of the entity that the DbSet will represent. + /// + /// + /// The type of the expression visitor that will be used to process LINQ expressions. + /// Can be used to mock EF Core specific expression handling, such as for ILike expressions. + /// + public static Mock> BuildMockDbSet(this ICollection data) + where TEntity : class + where TExpressionVisitor : ExpressionVisitor, new() + { + var mock = new Mock>(); + var enumerable = new TestAsyncEnumerableEfCore(data, entity => data.Remove(entity)); + mock.ConfigureAsyncEnumerableCalls(enumerable); + mock.As>().ConfigureQueryableCalls(enumerable, data.AsQueryable()); + mock.As>().Setup(x => x.GetAsyncEnumerator(It.IsAny())).Returns(() => enumerable.GetAsyncEnumerator()); + mock.Setup(m => m.AsQueryable()).Returns(enumerable); - mock.ConfigureDbSetCalls(data); - return mock; - } + mock.ConfigureDbSetCalls(data.AsQueryable()); + return mock; + } - private static void ConfigureDbSetCalls(this Mock> mock, IQueryable data) + private static void ConfigureDbSetCalls(this Mock> mock, IQueryable data) where TEntity : class { mock.Setup(m => m.AsQueryable()).Returns(mock.Object); mock.Setup(m => m.AsAsyncEnumerable()).Returns(CreateAsyncMock(data)); } - private static void ConfigureQueryableCalls( - this Mock> mock, - IQueryProvider queryProvider, - IQueryable data) where TEntity : class - { - mock.Setup(m => m.Provider).Returns(queryProvider); - mock.Setup(m => m.Expression).Returns(data?.Expression); - mock.Setup(m => m.ElementType).Returns(data?.ElementType); - mock.Setup(m => m.GetEnumerator()).Returns(() => data?.GetEnumerator()); + private static void ConfigureQueryableCalls( + this Mock> mock, + IQueryProvider queryProvider, + IQueryable data) where TEntity : class + { + mock.Setup(m => m.Provider).Returns(queryProvider); + mock.Setup(m => m.Expression).Returns(data?.Expression); + mock.Setup(m => m.ElementType).Returns(data?.ElementType); + mock.Setup(m => m.GetEnumerator()).Returns(() => data?.GetEnumerator()); - } + } - private static void ConfigureAsyncEnumerableCalls( - this Mock> mock, - IAsyncEnumerable enumerable)where TEntity : class - { - mock.Setup(d => d.GetAsyncEnumerator(It.IsAny())) - .Returns(() => enumerable.GetAsyncEnumerator()); - - } + private static void ConfigureAsyncEnumerableCalls( + this Mock> mock, + IAsyncEnumerable enumerable) where TEntity : class + { + mock.Setup(d => d.GetAsyncEnumerator(It.IsAny())) + .Returns(() => enumerable.GetAsyncEnumerator()); + + } - private static async IAsyncEnumerable CreateAsyncMock(IEnumerable data) - where TEntity : class - { - foreach (var entity in data) - { - yield return entity; - } + private static async IAsyncEnumerable CreateAsyncMock(IEnumerable data) + where TEntity : class + { + foreach (var entity in data) + { + yield return entity; + } - await Task.CompletedTask; - } - } + await Task.CompletedTask; + } + } } \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.NSubstitute/MockQueryable.NSubstitute.csproj b/src/MockQueryable/MockQueryable.NSubstitute/MockQueryable.NSubstitute.csproj index 3266042..5711113 100644 --- a/src/MockQueryable/MockQueryable.NSubstitute/MockQueryable.NSubstitute.csproj +++ b/src/MockQueryable/MockQueryable.NSubstitute/MockQueryable.NSubstitute.csproj @@ -1,7 +1,7 @@  - net6 + net8 MockQueryable.NSubstitute Roman Titov @@ -14,11 +14,14 @@ Mock EntityFrameworkCore Queryable mock EF EFCore UnitTests EntityFrameworkCore NSubstitute true - #80 Altered namespace for extension method to revert a breaking change - Thanks @StevePy + #81 Add support to ExecuteDelete and ExecuteUpdate - Thanks @lazaro-ansaldi and @Catlandor + #82 Update versions of Moq, NSubstitute and FakeItEasy to newer versions without known vulnerabilities - Thanks @Catlandor + #73 Supporting EF.Functions.Like and/or prossibility to provide cusotm ExpressionVisitor - Thanks @Catlandor + #66 Not suported with EF7: ExecuteDeleteAsync and ExecuteUpdateAsync - Thanks @Catlandor - 7.0.3 - 7.0.0.3 - 7.0.0.3 + 8.0.0 + 8.0.0.0 + 8.0.0.0 LICENSE README.md @@ -26,7 +29,7 @@ - + diff --git a/src/MockQueryable/MockQueryable.NSubstitute/NSubstituteExtensions.cs b/src/MockQueryable/MockQueryable.NSubstitute/NSubstituteExtensions.cs index 0db0998..5056907 100644 --- a/src/MockQueryable/MockQueryable.NSubstitute/NSubstituteExtensions.cs +++ b/src/MockQueryable/MockQueryable.NSubstitute/NSubstituteExtensions.cs @@ -1,8 +1,10 @@ using Microsoft.EntityFrameworkCore; +using MockQueryable.Core; using MockQueryable.EntityFrameworkCore; using NSubstitute; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; @@ -10,26 +12,69 @@ namespace MockQueryable.NSubstitute { public static class NSubstituteExtensions { - public static DbSet BuildMockDbSet(this IEnumerable data) where TEntity : class => data.BuildMock().BuildMockDbSet(); - public static DbSet BuildMockDbSet(this IQueryable data) where TEntity : class + /// + /// This method allows you to create a mock DbSet for testing purposes. + /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet + /// with custom expression handling, such as for testing LINQ queries or database operations. + /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements + /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration + /// and LINQ query capabilities. + /// + /// + /// The type of the entity that the DbSet will represent. + /// + public static DbSet BuildMockDbSet(this ICollection data) where TEntity : class + { + return BuildMockDbSet(data); + } + + /// + /// This method allows you to create a mock DbSet for testing purposes. + /// It is particularly useful when you want to simulate the behavior of Entity Framework Core's DbSet + /// with custom expression handling, such as for testing LINQ queries or database operations. + /// The method takes an IQueryable of the entity type and returns a mocked DbSet that implements + /// both IAsyncEnumerable and IQueryable interfaces, allowing for asynchronous enumeration + /// and LINQ query capabilities. + /// + /// + /// The type of the entity that the DbSet will represent. + /// + /// + /// The type of the expression visitor that will be used to process LINQ expressions. + /// Can be used to mock EF Core specific expression handling, such as for ILike expressions. + /// + public static DbSet BuildMockDbSet(this ICollection data) + where TEntity : class + where TExpressionVisitor : ExpressionVisitor, new() { var mock = Substitute.For, IQueryable, IAsyncEnumerable>(); - var enumerable = new TestAsyncEnumerableEfCore(data); + var enumerable = new TestAsyncEnumerableEfCore(data, entity => data.Remove(entity)); + ConfigureAllCalls(mock, enumerable, data); + + return mock; + } + + + + private static void ConfigureAllCalls( + this DbSet mock, + TestAsyncEnumerableEfCore enumerable, + ICollection data) + where TEntity : class + where TExpressionVisitor : ExpressionVisitor, new() + { mock.ConfigureAsyncEnumerableCalls(enumerable); - mock.ConfigureQueryableCalls(enumerable, data); - mock.ConfigureDbSetCalls(data); + mock.ConfigureQueryableCalls(enumerable, data.AsQueryable()); + mock.ConfigureDbSetCalls(data.AsQueryable()); if (mock is IAsyncEnumerable asyncEnumerable) { - asyncEnumerable.GetAsyncEnumerator(Arg.Any()).Returns(args => enumerable.GetAsyncEnumerator()); + asyncEnumerable.GetAsyncEnumerator(Arg.Any()).Returns(args => enumerable.GetAsyncEnumerator()); } - - return mock; } - private static void ConfigureQueryableCalls( this IQueryable mock, IQueryProvider queryProvider, diff --git a/src/MockQueryable/MockQueryable.Sample/MockQueryable.Sample.csproj b/src/MockQueryable/MockQueryable.Sample/MockQueryable.Sample.csproj index 2ebe7d8..8402916 100644 --- a/src/MockQueryable/MockQueryable.Sample/MockQueryable.Sample.csproj +++ b/src/MockQueryable/MockQueryable.Sample/MockQueryable.Sample.csproj @@ -1,18 +1,23 @@  - net6.0 + net8 - - - - + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/MockQueryable/MockQueryable.Sample/MyService.cs b/src/MockQueryable/MockQueryable.Sample/MyService.cs index 50d782b..e64c33c 100644 --- a/src/MockQueryable/MockQueryable.Sample/MyService.cs +++ b/src/MockQueryable/MockQueryable.Sample/MyService.cs @@ -1,96 +1,104 @@ -using System; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using AutoMapper; -using AutoMapper.QueryableExtensions; -using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; namespace MockQueryable.Sample { public class MyService { private readonly IUserRepository _userRepository; + private static readonly MapperConfiguration _mapperConfiguration = new( + cfg => + { + cfg.CreateMap() + .ForMember(dto => dto.FirstName, conf => conf.MapFrom(ol => ol.FirstName)) + .ForMember(dto => dto.LastName, conf => conf.MapFrom(ol => ol.LastName)); + }, + loggerFactory: new LoggerFactory()); public static void Initialize() { - Mapper.Initialize(cfg => cfg.CreateMap() - .ForMember(dto => dto.FirstName, conf => conf.MapFrom(ol => ol.FirstName)) - .ForMember(dto => dto.LastName, conf => conf.MapFrom(ol => ol.LastName))); - Mapper.Configuration.AssertConfigurationIsValid(); + _mapperConfiguration.AssertConfigurationIsValid(); } - public MyService(IUserRepository userRepository) - { - _userRepository = userRepository; - } + public MyService(IUserRepository userRepository) + { + _userRepository = userRepository; + } + + public async Task CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth) + { + var query = _userRepository.GetQueryable(); + + if (await query.AnyAsync(x => x.LastName == lastName && x.DateOfBirth == dateOfBirth)) + { + throw new ApplicationException("User already exist"); + } + + var existUser = await query.FirstOrDefaultAsync(x => x.FirstName == firstName); + if (existUser != null) + { + throw new ApplicationException("User with FirstName already exist"); + } + + if (await query.CountAsync(x => x.DateOfBirth == dateOfBirth.Date) > 3) + { + throw new ApplicationException("Users with DateOfBirth more than limit"); + } + + await _userRepository.CreateUser(new UserEntity + { + FirstName = firstName, + LastName = lastName, + DateOfBirth = dateOfBirth.Date, + }); + + } + + public async Task> GetUserReports(DateTime dateFrom, DateTime dateTo) + { + var query = _userRepository.GetQueryable(); + + query = query.Where(x => x.DateOfBirth >= dateFrom.Date); + query = query.Where(x => x.DateOfBirth <= dateTo.Date); + + return await query.Select(x => new UserReport + { + FirstName = x.FirstName, + LastName = x.LastName, + }).ToListAsync(); + } - public async Task CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth) + public async Task> GetUserReportsAutoMap(DateTime dateFrom, DateTime dateTo) { var query = _userRepository.GetQueryable(); - if (await query.AnyAsync(x => x.LastName == lastName && x.DateOfBirth == dateOfBirth)) - { - throw new ApplicationException("User already exist"); - } - - var existUser = await query.FirstOrDefaultAsync(x => x.FirstName == firstName); - if (existUser != null) - { - throw new ApplicationException("User with FirstName already exist"); - } - - if (await query.CountAsync(x => x.DateOfBirth == dateOfBirth.Date) > 3) - { - throw new ApplicationException("Users with DateOfBirth more than limit"); - } - - await _userRepository.CreateUser(new UserEntity - { - FirstName = firstName, - LastName = lastName, - DateOfBirth = dateOfBirth.Date, - }); + query = query.Where(x => x.DateOfBirth >= dateFrom.Date); + query = query.Where(x => x.DateOfBirth <= dateTo.Date); + return await query.ProjectTo(_mapperConfiguration).ToListAsync(); } + } - public async Task> GetUserReports(DateTime dateFrom, DateTime dateTo) + public interface IUserRepository { - var query = _userRepository.GetQueryable(); + IQueryable GetQueryable(); - query = query.Where(x => x.DateOfBirth >= dateFrom.Date); - query = query.Where(x => x.DateOfBirth <= dateTo.Date); + Task CreateUser(UserEntity user); - return await query.Select(x => new UserReport - { - FirstName = x.FirstName, - LastName = x.LastName, - }).ToListAsync(); - } + Task> GetAll(); + IAsyncEnumerable GetAllAsync(); - public async Task> GetUserReportsAutoMap(DateTime dateFrom, DateTime dateTo) - { - var query = _userRepository.GetQueryable(); + Task DeleteUserAsync(Guid id); - query = query.Where(x => x.DateOfBirth >= dateFrom.Date); - query = query.Where(x => x.DateOfBirth <= dateTo.Date); - - return await query.ProjectTo().ToListAsync(); + Task UpdateFirstAndLastNameByIdAsync(Guid id, string firstName); } - } - - public interface IUserRepository - { - IQueryable GetQueryable(); - - Task CreateUser(UserEntity user); - - Task> GetAll(); - - IAsyncEnumerable GetAllAsync(); - } - public class UserReport { @@ -98,11 +106,11 @@ public class UserReport public string LastName { get; set; } } - public class UserEntity - { - public Guid Id { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public DateTime DateOfBirth { get; set; } - } + public class UserEntity + { + public Guid Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public DateTime DateOfBirth { get; set; } + } } \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.Sample/MyServiceFakeItEasyTests.cs b/src/MockQueryable/MockQueryable.Sample/MyServiceFakeItEasyTests.cs index e74d2ee..bba01fc 100644 --- a/src/MockQueryable/MockQueryable.Sample/MyServiceFakeItEasyTests.cs +++ b/src/MockQueryable/MockQueryable.Sample/MyServiceFakeItEasyTests.cs @@ -1,47 +1,48 @@ -using System; +using FakeItEasy; +using Microsoft.EntityFrameworkCore; +using MockQueryable.FakeItEasy; +using NUnit.Framework; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using FakeItEasy; -using Microsoft.EntityFrameworkCore; -using MockQueryable.FakeItEasy; -using NUnit.Framework; -namespace MockQueryable.Sample +namespace MockQueryable.Sample; + +[TestFixture] +public class MyServiceFakeItEasyTests { - [TestFixture] - public class MyServiceFakeItEasyTests - { - private static readonly CultureInfo UsCultureInfo = new CultureInfo("en-US"); + private static readonly CultureInfo UsCultureInfo = new("en-US"); [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) { - //arrange - - var userRepository = A.Fake(); - var service = new MyService(userRepository); - var users = new List - { - new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {FirstName = "ExistFirstName"}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - }; - //expect - var mock = users.BuildMock(); - A.CallTo(() => userRepository.GetQueryable()).Returns(mock); - //act - var ex = Assert.ThrowsAsync(() => - service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); + // arrange + var userRepository = A.Fake(); + var service = new MyService(userRepository); + var users = new List + { + new() {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {FirstName = "ExistFirstName"}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + }; + + // expect + var mock = users.BuildMock(); + A.CallTo(() => userRepository.GetQueryable()).Returns(mock); + // act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + + // assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); } [TestCase("01/20/2012", "06/20/2018", 5)] @@ -50,39 +51,38 @@ public void CreateUserIfNotExist(string firstName, string lastName, DateTime dat [TestCase("01/20/2010", "02/20/2011", 0)] public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) { - //arrange - var userRepository = A.Fake(); - var service = new MyService(userRepository); - var users = CreateUserList(); - //expect - var mock = users.BuildMock(); - A.CallTo(() => userRepository.GetQueryable()).Returns(mock); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); - + //arrange + var userRepository = A.Fake(); + var service = new MyService(userRepository); + var users = TestDataHelper.CreateUserList(); + //expect + var mock = users.BuildMock(); + A.CallTo(() => userRepository.GetQueryable()).Returns(mock); + //act + var result = await service.GetUserReports(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } - [TestCase("01/20/2012", "06/20/2018", 5)] [TestCase("01/20/2012", "06/20/2012", 4)] [TestCase("01/20/2012", "02/20/2012", 3)] [TestCase("01/20/2010", "02/20/2011", 0)] public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) { - //arrange - var userRepository = A.Fake(); - var service = new MyService(userRepository); - var users = CreateUserList(); - //expect - var mock = users.BuildMock(); - A.CallTo(() => userRepository.GetQueryable()).Returns(mock); - //act - var result = await service.GetUserReportsAutoMap(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); + // arrange + var userRepository = A.Fake(); + var service = new MyService(userRepository); + var users = TestDataHelper.CreateUserList(); + // expect + var mock = users.BuildMock(); + A.CallTo(() => userRepository.GetQueryable()).Returns(mock); + + // act + var result = await service.GetUserReportsAutoMap(from, to); + // assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] @@ -90,24 +90,25 @@ public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expecte [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) { - //arrange - var users = new List - { - new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {FirstName = "ExistFirstName"}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - }; - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var ex = Assert.ThrowsAsync(() => - service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); + // arrange + var users = new List + { + new() {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {FirstName = "ExistFirstName"}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + }; + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + // act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + + // assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); } [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] @@ -115,87 +116,92 @@ public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTim [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] public void DbSetCreatedFromCollectionCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) { - //arrange + // arrange var users = new List { - new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {FirstName = "ExistFirstName"}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {FirstName = "ExistFirstName"}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, + new() {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, }; var mock = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mock); var service = new MyService(userRepository); - //act + // act var ex = Assert.ThrowsAsync(() => - service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); - + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + // assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); } - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) { - //arrange - var userEntities = new List(); - var mock = userEntities.AsQueryable().BuildMockDbSet(); - A.CallTo(() => mock.AddAsync(A._, A._)) - .ReturnsLazily(call => - { - userEntities.Add((UserEntity) call.Arguments[0]); - return default; - }); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); - // assert - var entity = mock.Single(); - Assert.AreEqual(firstName, entity.FirstName); - Assert.AreEqual(lastName, entity.LastName); - Assert.AreEqual(dateOfBirth, entity.DateOfBirth); + // arrange + var userEntities = new List(); + var mock = userEntities.BuildMockDbSet(); + A.CallTo(() => mock.AddAsync(A._, A._)) + .ReturnsLazily(call => + { + userEntities.Add((UserEntity)call.Arguments[0]); + return default; + }); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + + // act + await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); + + // assert + var entity = mock.Single(); + Assert.That(firstName, Is.EqualTo(entity.FirstName)); + Assert.That(lastName, Is.EqualTo(entity.LastName)); + Assert.That(dateOfBirth, Is.EqualTo(entity.DateOfBirth)); } [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] public async Task DbSetCreatedFromCollectionCreateUser1(string firstName, string lastName, DateTime dateOfBirth) { - //arrange + // arrange var userEntities = new List(); var mock = userEntities.BuildMockDbSet(); A.CallTo(() => mock.AddAsync(A._, A._)) - .ReturnsLazily(call => - { - userEntities.Add((UserEntity)call.Arguments[0]); - return default; - }); + .ReturnsLazily(call => + { + userEntities.Add((UserEntity)call.Arguments[0]); + return default; + }); var userRepository = new TestDbSetRepository(mock); var service = new MyService(userRepository); - //act + + // act await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); + // assert var entity = mock.Single(); - Assert.AreEqual(firstName, entity.FirstName); - Assert.AreEqual(lastName, entity.LastName); - Assert.AreEqual(dateOfBirth, entity.DateOfBirth); + Assert.That(firstName, Is.EqualTo(entity.FirstName)); + Assert.That(lastName, Is.EqualTo(entity.LastName)); + Assert.That(dateOfBirth, Is.EqualTo(entity.DateOfBirth)); } - [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2018", 5)] [TestCase("01/20/2012", "06/20/2012", 4)] [TestCase("01/20/2012", "02/20/2012", 3)] [TestCase("01/20/2010", "02/20/2011", 0)] public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) { - //arrange - var users = CreateUserList(); - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); + // arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + + // act + var result = await service.GetUserReports(from, to); + + // assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } [TestCase("01/20/2012", "06/20/2018", 5)] @@ -204,122 +210,257 @@ public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCo [TestCase("01/20/2010", "02/20/2011", 0)] public async Task DbSetCreatedFromCollectionGetUserReports(DateTime from, DateTime to, int expectedCount) { - //arrange - var users = CreateUserList(); + // arrange + var users = TestDataHelper.CreateUserList(); var mock = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mock); var service = new MyService(userRepository); - //act + + // act var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); + + // assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } - [TestCase] + [TestCase] public async Task DbSetGetAllUserEntitiesAsync() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetAllAsync().ToListAsync(); + + // assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } + + [Test] + public async Task DbSetCreatedFromCollectionGetAllUserEntitiesAsync() { // arrange - var users = CreateUserList(); + var users = TestDataHelper.CreateUserList(); - var mockDbSet = users.AsQueryable().BuildMockDbSet(); + var mockDbSet = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mockDbSet); // act var result = await userRepository.GetAllAsync().ToListAsync(); - // assert - Assert.AreEqual(users.Count, result.Count); + // assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } + + [Test] + public async Task DbSetGetAllUserEntitiesAsync_ShouldReturnAllEntities_WhenSourceIsChanged() + { + // arrange + var users = new List(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + + // act + var result1 = await userRepository.GetAllAsync().ToListAsync(); + users.AddRange(TestDataHelper.CreateUserList()); + var result2 = await userRepository.GetAllAsync().ToListAsync(); + + // assert + Assert.That(0, Is.EqualTo(result1.Count)); + Assert.That(users.Count, Is.EqualTo(result2.Count)); + } + + [Test] + public async Task DbSetGetAllUserEntity() + { + //arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + + //act + var result = await userRepository.GetAll(); + + //assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } + + [Test] + public async Task DbSetCreatedFromCollectionGetAllUserEntity() + { + // arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + + // act + var result = await userRepository.GetAll(); + + // assert + Assert.That(users.Count, Is.EqualTo(result.Count)); } [TestCase] - public async Task DbSetCreatedFromCollectionGetAllUserEntitiesAsync() + public void GetUsersByFirstName_ExpressionVisitorMissing_ThrowsException() { // arrange - var users = CreateUserList(); + var users = TestDataHelper.CreateUserList(); var mockDbSet = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mockDbSet); // act - var result = await userRepository.GetAllAsync().ToListAsync(); + var exception = Assert.ThrowsAsync(() => userRepository.GetUsersByFirstName("naME")); // assert - Assert.AreEqual(users.Count, result.Count); + Assert.That( + exception.Message, + Is.EqualTo( + "The 'Like' method is not supported because the query has switched to client-evaluation. " + + "This usually happens when the arguments to the method cannot be translated to server. " + + "Rewrite the query to avoid client evaluation of arguments so that method can be translated to server.")); } [TestCase] - public async Task DbSetToListAsyncAsync_ShouldReturnAllEntities_WhenSourceIsChanged() + public async Task GetUsersByFirstName_PartOfNameCaseInsensitiveSearch_AllMatchesReturned() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetUsersByFirstName("naME3"); + + // assert + Assert.That(result.Count, Is.EqualTo(2)); + } + + [TestCase] + public void GetUsersByLastName_ExpressionVisitorMissing_ThrowsException() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var exception = Assert.ThrowsAsync(() => userRepository.GetUsersByLastName("naME4")); + + // assert + Assert.That( + exception.Message, + Is.EqualTo( + "The 'ILike' method is not supported because the query has switched to client-evaluation. " + + "This usually happens when the arguments to the method cannot be translated to server. " + + "Rewrite the query to avoid client evaluation of arguments so that method can be translated to server.")); + } + + [TestCase] + public async Task GetUsersByLastName_PartOfNameCaseInsensitiveSearch_AllMatchesReturned() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetUsersByLastName("naME4"); + + // assert + Assert.That(result.Count, Is.EqualTo(3)); + } + + + + [Test] + public async Task DbSetCreatedFromCollection_ExecuteDeleteAsync() { // arrange - var users = new List(); + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); - var mockDbSet = users.AsQueryable().BuildMockDbSet(); - // act - var result1 = await mockDbSet.ToListAsync(); - users.AddRange(CreateUserList()); - var result2 = await mockDbSet.ToListAsync(); + var count = await userRepository.DeleteUserAsync(userId); // assert - Assert.AreEqual(0, result1.Count); - Assert.AreEqual(users.Count, result2.Count); + Assert.That(count, Is.EqualTo(1)); + var updatedUsers = await userRepository.GetAllAsync().ToListAsync(); + Assert.That(updatedUsers.Any(x => x.Id == userId), Is.EqualTo(false)); } - [TestCase] - public async Task DbSetGetAllUserEntity() + [Test] + public async Task DbSetCreatedFromCollectionExecuteDeleteAsync_ShouldReturnZero() { - //arrange - var users = CreateUserList(); - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + //act + var count = await userRepository.DeleteUserAsync(Guid.NewGuid()); + + // assert + Assert.That(count, Is.EqualTo(0)); + } + + [Test] + public async Task DbSetCreatedFromCollectionExecuteUpdateAsync() + { + // arrange + var expectedName = "Unit Test"; + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + //act - var result = await userRepository.GetAll(); + var count = await userRepository.UpdateFirstAndLastNameByIdAsync(userId, expectedName); + //assert - Assert.AreEqual(users.Count, result.Count); + Assert.That(count, Is.EqualTo(1)); + var user = users.Single(x => x.Id == userId); + Assert.That(expectedName, Is.EqualTo(user.FirstName)); + Assert.That(expectedName, Is.EqualTo(user.LastName)); } - [TestCase] - public async Task DbSetCreatedFromCollectionGetAllUserEntity() + [Test] + public async Task DbSetCreatedFromCollectionExecuteUpdateAsync_ShouldReturnZero() { - //arrange - var users = CreateUserList(); - var mock = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + var arrangeUser = users.Single(x => x.Id == userId); + var expectedFirstName = arrangeUser.FirstName; + var expectedLastName = arrangeUser.LastName; + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + //act - var result = await userRepository.GetAll(); + var count = await userRepository.UpdateFirstAndLastNameByIdAsync(Guid.NewGuid(), "Unit Test"); + //assert - Assert.AreEqual(users.Count, result.Count); + Assert.That(count, Is.EqualTo(0)); + + var user = users.Single(x => x.Id == userId); + Assert.That(expectedFirstName, Is.EqualTo(user.FirstName)); + Assert.That(expectedLastName, Is.EqualTo(user.LastName)); } - private static List CreateUserList() => new List - { - new UserEntity - { - FirstName = "FirstName1", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - FirstName = "FirstName2", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - FirstName = "FirstName3", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - FirstName = "FirstName3", LastName = "LastName", - DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - FirstName = "FirstName5", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) - }, - }; - - - } -} + + +} \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.Sample/MyServiceMoqTests.cs b/src/MockQueryable/MockQueryable.Sample/MyServiceMoqTests.cs index c7cec20..d9e3b1f 100644 --- a/src/MockQueryable/MockQueryable.Sample/MyServiceMoqTests.cs +++ b/src/MockQueryable/MockQueryable.Sample/MyServiceMoqTests.cs @@ -1,45 +1,47 @@ -using System; +using Microsoft.EntityFrameworkCore; +using MockQueryable.Moq; +using Moq; +using NUnit.Framework; +using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using MockQueryable.Moq; -using Moq; -using NUnit.Framework; -namespace MockQueryable.Sample +namespace MockQueryable.Sample; + +[TestFixture] +public class MyServiceMoqTests { - [TestFixture] - public class MyServiceMoqTests - { - private static readonly CultureInfo UsCultureInfo = new CultureInfo("en-US"); + [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) { - //arrange - var userRepository = new Mock(); - var service = new MyService(userRepository.Object); - var users = new List - { - new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {FirstName = "ExistFirstName"}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)} - }; - //expect - var mock = users.BuildMock(); - userRepository.Setup(x => x.GetQueryable()).Returns(mock); - //act - var ex = Assert.ThrowsAsync(() => - service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); + //arrange + var userRepository = new Mock(); + var service = new MyService(userRepository.Object); + var users = new List + { + new() + { + LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) + }, + new() { FirstName = "ExistFirstName" }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) } + }; + //expect + var mock = users.BuildMock(); + userRepository.Setup(x => x.GetQueryable()).Returns(mock); + //act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + //assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); } [TestCase("01/20/2012", "06/20/2018", 5)] @@ -48,107 +50,111 @@ public void CreateUserIfNotExist(string firstName, string lastName, DateTime dat [TestCase("01/20/2010", "02/20/2011", 0)] public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) { - //arrange - var userRepository = new Mock(); - var service = new MyService(userRepository.Object); - var users = CreateUserList(); - //expect - var mock = users.BuildMock(); - userRepository.Setup(x => x.GetQueryable()).Returns(mock); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); + //arrange + var userRepository = new Mock(); + var service = new MyService(userRepository.Object); + var users = TestDataHelper.CreateUserList(); + //expect + var mock = users.BuildMock(); + userRepository.Setup(x => x.GetQueryable()).Returns(mock); + //act + var result = await service.GetUserReports(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } - - [TestCase("01/20/2012", "06/20/2018", 5)] [TestCase("01/20/2012", "06/20/2012", 4)] [TestCase("01/20/2012", "02/20/2012", 3)] [TestCase("01/20/2010", "02/20/2011", 0)] public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) { - //arrange - var userRepository = new Mock(); - var service = new MyService(userRepository.Object); - var users = CreateUserList(); - //expect - var mock = users.BuildMock(); - userRepository.Setup(x => x.GetQueryable()).Returns(mock); - //act - var result = await service.GetUserReportsAutoMap(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); + //arrange + var userRepository = new Mock(); + var service = new MyService(userRepository.Object); + var users = TestDataHelper.CreateUserList(); + //expect + var mock = users.BuildMock(); + userRepository.Setup(x => x.GetQueryable()).Returns(mock); + //act + var result = await service.GetUserReportsAutoMap(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } - [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) { - //arrange - var users = new List - { - new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {FirstName = "ExistFirstName"}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)} - }; - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock.Object); - var service = new MyService(userRepository); - //act - var ex = Assert.ThrowsAsync(() => - service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); + //arrange + var users = new List + { + new() + { + LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) + }, + new() { FirstName = "ExistFirstName" }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) } + }; + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock.Object); + var service = new MyService(userRepository); + //act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + //assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); } [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] - public void DbSetCreatedFromCollectionCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) + public void DbSetCreatedFromCollectionCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, + string expectedError) { //arrange var users = new List { - new UserEntity {LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {FirstName = "ExistFirstName"}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)}, - new UserEntity {DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat)} + new() + { + LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) + }, + new() { FirstName = "ExistFirstName" }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", TestDataHelper.UsCultureInfo.DateTimeFormat) } }; var mock = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mock.Object); var service = new MyService(userRepository); //act var ex = Assert.ThrowsAsync(() => - service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); //assert - Assert.AreEqual(expectedError, ex.Message); + Assert.That(expectedError, Is.EqualTo(ex.Message)); } - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) { - //arrange - var userEntities = new List(); - var mock = userEntities.AsQueryable().BuildMockDbSet(); - - mock.Setup(set => set.AddAsync(It.IsAny(), It.IsAny())) - .Callback((UserEntity entity, CancellationToken _) => userEntities.Add(entity)); - var userRepository = new TestDbSetRepository(mock.Object); - var service = new MyService(userRepository); - //act - await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); - // assert - var entity = mock.Object.Single(); - Assert.AreEqual(firstName, entity.FirstName); - Assert.AreEqual(lastName, entity.LastName); - Assert.AreEqual(dateOfBirth, entity.DateOfBirth); + //arrange + var userEntities = new List(); + var mock = userEntities.BuildMockDbSet(); + + mock.Setup(set => set.AddAsync(It.IsAny(), It.IsAny())) + .Callback((UserEntity entity, CancellationToken _) => userEntities.Add(entity)); + var userRepository = new TestDbSetRepository(mock.Object); + var service = new MyService(userRepository); + //act + await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); + // assert + var entity = mock.Object.Single(); + Assert.That(firstName, Is.EqualTo(entity.FirstName)); + Assert.That(lastName, Is.EqualTo(entity.LastName)); + Assert.That(dateOfBirth, Is.EqualTo(entity.DateOfBirth)); } [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] @@ -166,26 +172,26 @@ public async Task DbSetCreatedFromCollectionCreateUser(string firstName, string await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); // assert var entity = mock.Object.Single(); - Assert.AreEqual(firstName, entity.FirstName); - Assert.AreEqual(lastName, entity.LastName); - Assert.AreEqual(dateOfBirth, entity.DateOfBirth); + Assert.That(firstName, Is.EqualTo(entity.FirstName)); + Assert.That(lastName, Is.EqualTo(entity.LastName)); + Assert.That(dateOfBirth, Is.EqualTo(entity.DateOfBirth)); } - [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2018", 5)] [TestCase("01/20/2012", "06/20/2012", 4)] [TestCase("01/20/2012", "02/20/2012", 3)] [TestCase("01/20/2010", "02/20/2011", 0)] public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) { - //arrange - var users = CreateUserList(); - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock.Object); - var service = new MyService(userRepository); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); + //arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock.Object); + var service = new MyService(userRepository); + //act + var result = await service.GetUserReports(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); } [TestCase("01/20/2012", "06/20/2018", 5)] @@ -195,137 +201,71 @@ public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCo public async Task DbSetCreatedFromCollectionGetUserReports(DateTime from, DateTime to, int expectedCount) { //arrange - var users = CreateUserList(); + var users = TestDataHelper.CreateUserList(); var mock = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mock.Object); var service = new MyService(userRepository); //act var result = await service.GetUserReports(from, to); //assert - Assert.AreEqual(expectedCount, result.Count); + Assert.That(expectedCount, Is.EqualTo(result.Count)); } - [TestCase] + [TestCase] public async Task DbSetGetAllUserEntity() { - //arrange - var users = CreateUserList(); - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock.Object); - //act - var result = await userRepository.GetAll(); - //assert - Assert.AreEqual(users.Count, result.Count); + //arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock.Object); + //act + var result = await userRepository.GetAll(); + //assert + Assert.That(users.Count, Is.EqualTo(result.Count)); } [TestCase] public async Task DbSetCreatedFromCollectionGetAllUserEntity() { //arrange - var users = CreateUserList(); + var users = TestDataHelper.CreateUserList(); var mock = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mock.Object); //act var result = await userRepository.GetAll(); //assert - Assert.AreEqual(users.Count, result.Count); + Assert.That(users.Count, Is.EqualTo(result.Count)); } - [TestCase] + [TestCase] public async Task DbSetFindAsyncUserEntity() { - //arrange - var userId = Guid.NewGuid(); - var users = new List - { - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName1", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName2", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = userId, - FirstName = "FirstName3", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName3", LastName = "LastName", - DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity + //arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mock = users.BuildMockDbSet(); + mock.Setup(x => x.FindAsync(It.IsAny())).ReturnsAsync((object[] ids) => { - Id = Guid.NewGuid(), - FirstName = "FirstName5", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) - } - }; - - var mock = users.AsQueryable().BuildMockDbSet(); - mock.Setup(x => x.FindAsync(It.IsAny())).ReturnsAsync((object[] ids) => - { - var id = (Guid) ids.First(); - return users.FirstOrDefault(x => x.Id == id); - }); - var userRepository = new TestDbSetRepository(mock.Object); - - //act - var result = await ((DbSet)userRepository.GetQueryable()).FindAsync(userId); - - //assert - Assert.IsNotNull(result); - Assert.AreEqual("FirstName3", result.FirstName); - } + var id = (Guid)ids.First(); + return users.FirstOrDefault(x => x.Id == id); + }); + var userRepository = new TestDbSetRepository(mock.Object); + //act + var result = await ((DbSet)userRepository.GetQueryable()).FindAsync(userId); + + //assert + Assert.That(result, Is.Not.Null); + Assert.That("FirstName1", Is.EqualTo(result.FirstName)); + } [TestCase] public async Task DbSetCreatedFromCollectionFindAsyncUserEntity() { //arrange var userId = Guid.NewGuid(); - var users = new List - { - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName1", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName2", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = userId, - FirstName = "FirstName3", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName3", LastName = "LastName", - DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) - }, - new UserEntity - { - Id = Guid.NewGuid(), - FirstName = "FirstName5", LastName = "LastName", - DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) - } - }; - + var users = TestDataHelper.CreateUserList(userId); var mock = users.BuildMockDbSet(); mock.Setup(x => x.FindAsync(It.IsAny())).ReturnsAsync((object[] ids) => { @@ -338,52 +278,50 @@ public async Task DbSetCreatedFromCollectionFindAsyncUserEntity() var result = await ((DbSet)userRepository.GetQueryable()).FindAsync(userId); //assert - Assert.IsNotNull(result); - Assert.AreEqual("FirstName3", result.FirstName); + Assert.That(result, Is.Not.Null); + Assert.That("FirstName1", Is.EqualTo(result.FirstName)); } - [TestCase] + [TestCase] public async Task DbSetGetAllUserEntitiesAsync() { - // arrange - var users = CreateUserList(); + // arrange + var users = TestDataHelper.CreateUserList(); - var mockDbSet = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mockDbSet.Object); + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); - // act - var result = await userRepository.GetAllAsync().ToListAsync(); + // act + var result = await userRepository.GetAllAsync().ToListAsync(); - // assert - Assert.AreEqual(users.Count, result.Count); + // assert + Assert.That(users.Count, Is.EqualTo(result.Count)); } - - + [TestCase] public async Task DbSetToListAsyncAsync_ShouldReturnAllEntities_WhenSourceIsChanged() { - // arrange - var users = new List(); + // arrange + var users = new List(); - var mockDbSet = users.AsQueryable().BuildMockDbSet(); + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); - // act - var result1 = await mockDbSet.Object.ToListAsync(); - users.AddRange(CreateUserList()); - var result2 = await mockDbSet.Object.ToListAsync(); + // act + var result1 = await userRepository.GetAllAsync().ToListAsync(); + users.AddRange( TestDataHelper.CreateUserList()); + var result2 = await userRepository.GetAllAsync().ToListAsync(); - // assert - Assert.AreEqual(0, result1.Count); - Assert.AreEqual(users.Count, result2.Count); + // assert + Assert.That(0, Is.EqualTo(result1.Count)); + Assert.That(users.Count, Is.EqualTo(result2.Count)); } - - [TestCase] public async Task DbSetCreatedFromCollectionGetAllUserEntitiesAsync() { // arrange - var users = CreateUserList(); + var users = TestDataHelper.CreateUserList(); var mockDbSet = users.BuildMockDbSet(); var userRepository = new TestDbSetRepository(mockDbSet.Object); @@ -392,16 +330,167 @@ public async Task DbSetCreatedFromCollectionGetAllUserEntitiesAsync() var result = await userRepository.GetAllAsync().ToListAsync(); // assert - Assert.AreEqual(users.Count, result.Count); + Assert.That(users.Count, Is.EqualTo(result.Count)); + } + + [TestCase] + public void GetUsersByFirstName_ExpressionVisitorMissing_ThrowsException() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + // act + var exception = + Assert.ThrowsAsync(() => userRepository.GetUsersByFirstName("naME4")); + + // assert + Assert.That( + exception.Message, + Is.EqualTo( + "The 'Like' method is not supported because the query has switched to client-evaluation. " + + "This usually happens when the arguments to the method cannot be translated to server. " + + "Rewrite the query to avoid client evaluation of arguments so that method can be translated to server.")); + } + + + [TestCase] + public async Task GetUsersByFirstName_PartOfNameCaseInsensitiveSearch_AllMatchesReturned() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + // act + var result = await userRepository.GetUsersByFirstName("naME3"); + + // assert + Assert.That(result.Count(), Is.EqualTo(2)); + } + + [TestCase] + public void GetUsersByLastName_ExpressionVisitorMissing_ThrowsException() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + // act + var exception = Assert.ThrowsAsync(() => userRepository.GetUsersByLastName("naME4")); + + // assert + Assert.That( + exception.Message, + Is.EqualTo( + "The 'ILike' method is not supported because the query has switched to client-evaluation. " + + "This usually happens when the arguments to the method cannot be translated to server. " + + "Rewrite the query to avoid client evaluation of arguments so that method can be translated to server.")); + } + + [TestCase] + public async Task GetUsersByLastName_PartOfNameCaseInsensitiveSearch_AllMatchesReturned() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + // act + var result = await userRepository.GetUsersByLastName("naME4"); + + // assert + Assert.That(result.Count(), Is.EqualTo(3)); + } + + + [Test] + public async Task DbSetCreatedFromCollection_ExecuteDeleteAsync() + { + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + // act + var count = await userRepository.DeleteUserAsync(userId); + + // assert + Assert.That(count, Is.EqualTo(1)); + var updatedUsers = await userRepository.GetAllAsync().ToListAsync(); + Assert.That(updatedUsers.Any(x => x.Id == userId), Is.EqualTo(false)); + + } + + [Test] + public async Task DbSetCreatedFromCollectionExecuteDeleteAsync_ShouldReturnZero() + { + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + //act + var count = await userRepository.DeleteUserAsync(Guid.NewGuid()); + + // assert + Assert.That(count, Is.EqualTo(0)); + } - private static List CreateUserList() => new List + [Test] + public async Task DbSetCreatedFromCollectionExecuteUpdateAsync() { - new UserEntity { FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) }, - }; - } + // arrange + var expectedName = "Unit Test"; + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + //act + var count = await userRepository.UpdateFirstAndLastNameByIdAsync(userId, expectedName); + + //assert + Assert.That(count, Is.EqualTo(1)); + var user = users.Single(x => x.Id == userId); + Assert.That(expectedName, Is.EqualTo(user.FirstName)); + Assert.That(expectedName, Is.EqualTo(user.LastName)); + } + + [Test] + public async Task DbSetCreatedFromCollectionExecuteUpdateAsync_ShouldReturnZero() + { + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + var arrangeUser = users.Single(x => x.Id == userId); + var expectedFirstName = arrangeUser.FirstName; + var expectedLastName = arrangeUser.LastName; + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet.Object); + + //act + var count = await userRepository.UpdateFirstAndLastNameByIdAsync(Guid.NewGuid(), "Unit Test"); + + //assert + Assert.That(count, Is.EqualTo(0)); + + var user = users.Single(x => x.Id == userId); + Assert.That(expectedFirstName, Is.EqualTo(user.FirstName)); + Assert.That(expectedLastName, Is.EqualTo(user.LastName)); + } + + } \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.Sample/MyServiceNSubstituteTests.cs b/src/MockQueryable/MockQueryable.Sample/MyServiceNSubstituteTests.cs index 1f9e08c..e8514d4 100644 --- a/src/MockQueryable/MockQueryable.Sample/MyServiceNSubstituteTests.cs +++ b/src/MockQueryable/MockQueryable.Sample/MyServiceNSubstituteTests.cs @@ -7,345 +7,507 @@ using System.Linq; using System.Threading.Tasks; -namespace MockQueryable.Sample +namespace MockQueryable.Sample; + +[TestFixture] +public class MyServiceNSubstituteTests { - [TestFixture] - public class MyServiceNSubstituteTests + private static readonly CultureInfo UsCultureInfo = new("en-US"); + + [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] + [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] + public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) { - private static readonly CultureInfo UsCultureInfo = new CultureInfo("en-US"); - - - [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] - [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] - public void CreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) - { - //arrange - var userRepository = Substitute.For(); - var service = new MyService(userRepository); - var users = new List - { - new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{FirstName = "ExistFirstName"}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - }; - //expect - var mock = users.BuildMock(); - userRepository.GetQueryable().Returns(mock); - //act - var ex= Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); - - } - - [TestCase("01/20/2012", "06/20/2018",5)] - [TestCase("01/20/2012", "06/20/2012",4)] - [TestCase("01/20/2012", "02/20/2012",3)] - [TestCase("01/20/2010", "02/20/2011",0)] - public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) - { - //arrange - var userRepository = Substitute.For(); - var service = new MyService(userRepository); - List users = CreateUserList(); - - //expect - var mock = users.BuildMock(); - userRepository.GetQueryable().Returns(mock); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); - } - - [TestCase("01/20/2012", "06/20/2018", 5)] - [TestCase("01/20/2012", "06/20/2012", 4)] - [TestCase("01/20/2012", "02/20/2012", 3)] - [TestCase("01/20/2010", "02/20/2011", 0)] - public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) - { - //arrange - List users = CreateUserList(); - - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var result = await service.GetUserReportsAutoMap(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); - - } - - [TestCase("01/20/2012", "06/20/2018", 5)] - [TestCase("01/20/2012", "06/20/2012", 4)] - [TestCase("01/20/2012", "02/20/2012", 3)] - [TestCase("01/20/2010", "02/20/2011", 0)] - public async Task GetUserReports_AutoMap_FromDbSetCreatedFromCollection(DateTime from, DateTime to, int expectedCount) - { - //arrange - List users = CreateUserList(); - - var mock = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var result = await service.GetUserReportsAutoMap(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); - - } - - [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] - [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] - public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) + //arrange + var userRepository = Substitute.For(); + var service = new MyService(userRepository); + var users = new List { - //arrange - var users = new List + new() { - new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{FirstName = "ExistFirstName"}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - }; - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var ex = Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); - - } - - - [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] - [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] - public void DbSetCreatedFromCollectionCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, string expectedError) + LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) + }, + new() { FirstName = "ExistFirstName" }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + }; + //expect + var mock = users.BuildMock(); + userRepository.GetQueryable().Returns(mock); + //act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + //assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); + } + + [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2012", 4)] + [TestCase("01/20/2012", "02/20/2012", 3)] + [TestCase("01/20/2010", "02/20/2011", 0)] + public async Task GetUserReports(DateTime from, DateTime to, int expectedCount) + { + //arrange + var userRepository = Substitute.For(); + var service = new MyService(userRepository); + List users = TestDataHelper.CreateUserList(); + + //expect + var mock = users.BuildMock(); + userRepository.GetQueryable().Returns(mock); + //act + var result = await service.GetUserReports(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); + } + + [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2012", 4)] + [TestCase("01/20/2012", "02/20/2012", 3)] + [TestCase("01/20/2010", "02/20/2011", 0)] + public async Task GetUserReports_AutoMap(DateTime from, DateTime to, int expectedCount) + { + //arrange + List users = TestDataHelper.CreateUserList(); + + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + var result = await service.GetUserReportsAutoMap(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); + } + + [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2012", 4)] + [TestCase("01/20/2012", "02/20/2012", 3)] + [TestCase("01/20/2010", "02/20/2011", 0)] + public async Task GetUserReports_AutoMap_FromDbSetCreatedFromCollection(DateTime from, DateTime to, + int expectedCount) + { + //arrange + List users = TestDataHelper.CreateUserList(); + + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + var result = await service.GetUserReportsAutoMap(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); + } + + [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] + [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] + public void DbSetCreateUserIfNotExist(string firstName, string lastName, DateTime dateOfBirth, + string expectedError) + { + //arrange + var users = new List { - //arrange - var users = new List + new() { - new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{FirstName = "ExistFirstName"}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - new UserEntity{DateOfBirth = DateTime.Parse("01/20/2012",UsCultureInfo.DateTimeFormat)}, - }; - var mock = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var ex = Assert.ThrowsAsync(() => service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); - //assert - Assert.AreEqual(expectedError, ex.Message); - - } - - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] - public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) - { - //arrange - var userEntities = new List(); - var mock = userEntities.AsQueryable().BuildMockDbSet(); - mock.AddAsync(Arg.Any()) - .Returns(info => null) - .AndDoes(info => userEntities.Add(info.Arg())); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); - // assert - var entity = mock.Single(); - Assert.AreEqual(firstName, entity.FirstName); - Assert.AreEqual(lastName, entity.LastName); - Assert.AreEqual(dateOfBirth, entity.DateOfBirth); - } - - [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] - public async Task DbSetCreatedFromCollectionCreateUser(string firstName, string lastName, DateTime dateOfBirth) - { - //arrange - var userEntities = new List(); - var mock = userEntities.BuildMockDbSet(); - mock.AddAsync(Arg.Any()) - .Returns(info => null) - .AndDoes(info => userEntities.Add(info.Arg())); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); - // assert - var entity = mock.Single(); - Assert.AreEqual(firstName, entity.FirstName); - Assert.AreEqual(lastName, entity.LastName); - Assert.AreEqual(dateOfBirth, entity.DateOfBirth); - } - - [TestCase("01/20/2012", "06/20/2018", 5)] - [TestCase("01/20/2012", "06/20/2012", 4)] - [TestCase("01/20/2012", "02/20/2012", 3)] - [TestCase("01/20/2010", "02/20/2011", 0)] - public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) - { - //arrange - var users = CreateUserList(); - - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); - } - - [TestCase("01/20/2012", "06/20/2018", 5)] - [TestCase("01/20/2012", "06/20/2012", 4)] - [TestCase("01/20/2012", "02/20/2012", 3)] - [TestCase("01/20/2010", "02/20/2011", 0)] - public async Task DbSetCreatedFromCollectionGetUserReports(DateTime from, DateTime to, int expectedCount) - { - //arrange - var users = CreateUserList(); - - var mock = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - var service = new MyService(userRepository); - //act - var result = await service.GetUserReports(from, to); - //assert - Assert.AreEqual(expectedCount, result.Count); - } - - [TestCase] - public async Task DbSetGetAllUserEntity() - { - //arrange - var users = CreateUserList(); - var mock = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - //act - var result = await userRepository.GetAll(); - //assert - Assert.AreEqual(users.Count, result.Count); - } - - [TestCase] - public async Task DbSetCreatedFromCollectionGetAllUserEntity() - { - //arrange - var users = CreateUserList(); - var mock = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mock); - //act - var result = await userRepository.GetAll(); - //assert - Assert.AreEqual(users.Count, result.Count); - } - - [TestCase] - public async Task DbSetGetAllUserEntitiesAsync() - { - // arrange - var users = CreateUserList(); - - var mockDbSet = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mockDbSet); - - // act - var result = await userRepository.GetAllAsync().ToListAsync(); - - // assert - Assert.AreEqual(users.Count, result.Count); - } - - - [TestCase] - public async Task DbSetGetAllUserEntitiesAsync_ShouldReturnAllEntities_WhenSourceIsChanged() + LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) + }, + new() { FirstName = "ExistFirstName" }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + }; + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + //assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); + } + + [TestCase("AnyFirstName", "AnyExistLastName", "01/20/2012", "Users with DateOfBirth more than limit")] + [TestCase("ExistFirstName", "AnyExistLastName", "02/20/2012", "User with FirstName already exist")] + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012", "User already exist")] + public void DbSetCreatedFromCollectionCreateUserIfNotExist(string firstName, string lastName, + DateTime dateOfBirth, string expectedError) + { + //arrange + var users = new List { - // arrange - var users = new List(); + new() + { + LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) + }, + new() { FirstName = "ExistFirstName" }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + new() { DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, + }; + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + var ex = Assert.ThrowsAsync(() => + service.CreateUserIfNotExist(firstName, lastName, dateOfBirth)); + //assert + Assert.That(expectedError, Is.EqualTo(ex.Message)); + } - var mockDbSet = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mockDbSet); + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] + public async Task DbSetCreateUser(string firstName, string lastName, DateTime dateOfBirth) + { + //arrange + var userEntities = new List(); + var mock = userEntities.BuildMockDbSet(); + mock.AddAsync(Arg.Any()) + .Returns(info => null) + .AndDoes(info => userEntities.Add(info.Arg())); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); + // assert + var entity = mock.Single(); + Assert.That(firstName, Is.EqualTo(entity.FirstName)); + Assert.That(lastName, Is.EqualTo(entity.LastName)); + Assert.That(dateOfBirth, Is.EqualTo(entity.DateOfBirth)); + } - // act - var result1 = await userRepository.GetAllAsync().ToListAsync(); - users.AddRange(CreateUserList()); - var result2 = await userRepository.GetAllAsync().ToListAsync(); + [TestCase("AnyFirstName", "ExistLastName", "01/20/2012")] + public async Task DbSetCreatedFromCollectionCreateUser(string firstName, string lastName, DateTime dateOfBirth) + { + //arrange + var userEntities = new List(); + var mock = userEntities.BuildMockDbSet(); + mock.AddAsync(Arg.Any()) + .Returns(info => null) + .AndDoes(info => userEntities.Add(info.Arg())); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + await service.CreateUserIfNotExist(firstName, lastName, dateOfBirth); + // assert + var entity = mock.Single(); + Assert.That(firstName, Is.EqualTo(entity.FirstName)); + Assert.That(lastName, Is.EqualTo(entity.LastName)); + Assert.That(dateOfBirth, Is.EqualTo(entity.DateOfBirth)); + } - // assert - Assert.AreEqual(0, result1.Count); - Assert.AreEqual(users.Count, result2.Count); - } + [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2012", 4)] + [TestCase("01/20/2012", "02/20/2012", 3)] + [TestCase("01/20/2010", "02/20/2011", 0)] + public async Task DbSetGetUserReports(DateTime from, DateTime to, int expectedCount) + { + //arrange + var users = TestDataHelper.CreateUserList(); + + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + var result = await service.GetUserReports(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); + } - [TestCase] - public async Task DbSetCreatedFromCollectionGetAllUserEntitiesAsync() - { - // arrange - var users = CreateUserList(); + [TestCase("01/20/2012", "06/20/2018", 5)] + [TestCase("01/20/2012", "06/20/2012", 4)] + [TestCase("01/20/2012", "02/20/2012", 3)] + [TestCase("01/20/2010", "02/20/2011", 0)] + public async Task DbSetCreatedFromCollectionGetUserReports(DateTime from, DateTime to, int expectedCount) + { + //arrange + var users = TestDataHelper.CreateUserList(); + + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + var service = new MyService(userRepository); + //act + var result = await service.GetUserReports(from, to); + //assert + Assert.That(expectedCount, Is.EqualTo(result.Count)); + } - var mockDbSet = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mockDbSet); + [TestCase] + public async Task DbSetGetAllUserEntity() + { + //arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + //act + var result = await userRepository.GetAll(); + //assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } - // act - var result = await userRepository.GetAllAsync().ToListAsync(); + [TestCase] + public async Task DbSetCreatedFromCollectionGetAllUserEntity() + { + //arrange + var users = TestDataHelper.CreateUserList(); + var mock = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mock); + //act + var result = await userRepository.GetAll(); + //assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } - // assert - Assert.AreEqual(users.Count, result.Count); - } + [TestCase] + public async Task DbSetGetAllUserEntitiesAsync() + { + // arrange + var users = TestDataHelper.CreateUserList(); - [TestCase] - public async Task DbSetGetOneUserTntityAsync() - { - // arrange - var users = CreateUserList(); + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); - var mockDbSet = users.AsQueryable().BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mockDbSet); + // act + var result = await userRepository.GetAllAsync().ToListAsync(); - // act - var result = await userRepository.GetAllAsync() - .Where(user => user.FirstName == "FirstName1") - .FirstOrDefaultAsync(); + // assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } - // assert - Assert.AreEqual(users.First(), result); - } + [TestCase] + public async Task DbSetGetAllUserEntitiesAsync_ShouldReturnAllEntities_WhenSourceIsChanged() + { + // arrange + var users = new List(); - [TestCase] - public async Task DbSetCreatedFromCollectionGetOneUserTntityAsync() - { - // arrange - var users = CreateUserList(); + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); - var mockDbSet = users.BuildMockDbSet(); - var userRepository = new TestDbSetRepository(mockDbSet); + // act + var result1 = await userRepository.GetAllAsync().ToListAsync(); + users.AddRange(TestDataHelper.CreateUserList()); + var result2 = await userRepository.GetAllAsync().ToListAsync(); - // act - var result = await userRepository.GetAllAsync() - .Where(user => user.FirstName == "FirstName1") - .FirstOrDefaultAsync(); + // assert + Assert.That(0, Is.EqualTo(result1.Count)); + Assert.That(users.Count, Is.EqualTo(result2.Count)); + } - // assert - Assert.AreEqual(users.First(), result); - } + [TestCase] + public async Task DbSetCreatedFromCollectionGetAllUserEntitiesAsync() + { + // arrange + var users = TestDataHelper.CreateUserList(); - private static List CreateUserList() => new List - { - new UserEntity { FirstName = "FirstName1", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName2", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName3", LastName = "LastName", DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) }, - new UserEntity { FirstName = "FirstName5", LastName = "LastName", DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) }, - }; + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetAllAsync().ToListAsync(); + + // assert + Assert.That(users.Count, Is.EqualTo(result.Count)); + } + + [TestCase] + public async Task DbSetGetOneUserTntityAsync() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetAllAsync() + .Where(user => user.FirstName == "FirstName1") + .FirstOrDefaultAsync(); + + // assert + Assert.That(users.First(), Is.EqualTo(result)); + } + + [TestCase] + public async Task DbSetCreatedFromCollectionGetOneUserTntityAsync() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetAllAsync() + .Where(user => user.FirstName == "FirstName1") + .FirstOrDefaultAsync(); + + // assert + Assert.That(users.First(), Is.EqualTo(result)); + } + + [TestCase] + public void GetUsersByFirstName_ExpressionVisitorMissing_ThrowsException() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var exception = + Assert.ThrowsAsync(() => userRepository.GetUsersByFirstName("naME")); + + // assert + Assert.That( + exception.Message, + Is.EqualTo( + "The 'Like' method is not supported because the query has switched to client-evaluation. " + + "This usually happens when the arguments to the method cannot be translated to server. " + + "Rewrite the query to avoid client evaluation of arguments so that method can be translated to server.")); + } + + + + [TestCase] + public async Task GetUsersByFirstName_PartOfNameCaseInsensitiveSearch_AllMatchesReturned() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + // act + var result = await userRepository.GetUsersByFirstName("naME3"); + + // assert + Assert.That(result.Count, Is.EqualTo(2)); + } + + + + [TestCase] + public void GetUsersByLastName_ExpressionVisitorMissing_ThrowsException() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var exception = + Assert.ThrowsAsync(() => userRepository.GetUsersByLastName("naME4")); + + // assert + Assert.That( + exception.Message, + Is.EqualTo( + "The 'ILike' method is not supported because the query has switched to client-evaluation. " + + "This usually happens when the arguments to the method cannot be translated to server. " + + "Rewrite the query to avoid client evaluation of arguments so that method can be translated to server.")); + } + + + + [TestCase] + public async Task GetUsersByLastName_PartOfNameCaseInsensitiveSearch_AllMatchesReturned() + { + // arrange + var users = TestDataHelper.CreateUserList(); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var result = await userRepository.GetUsersByLastName("naME4"); + + // assert + Assert.That(result.Count, Is.EqualTo(3)); + } + + + + [Test] + public async Task DbSetCreatedFromCollection_ExecuteDeleteAsync() + { + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + // act + var count = await userRepository.DeleteUserAsync(userId); + + // assert + Assert.That(count, Is.EqualTo(1)); + var updatedUsers = await userRepository.GetAllAsync().ToListAsync(); + Assert.That(updatedUsers.Any(x => x.Id == userId), Is.EqualTo(false)); + } + + [Test] + public async Task DbSetCreatedFromCollectionExecuteDeleteAsync_ShouldReturnZero() + { + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + //act + var count = await userRepository.DeleteUserAsync(Guid.NewGuid()); + + // assert + Assert.That(count, Is.EqualTo(0)); + } + + [Test] + public async Task DbSetCreatedFromCollectionExecuteUpdateAsync() + { + // arrange + var expectedName = "Unit Test"; + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + //act + var count = await userRepository.UpdateFirstAndLastNameByIdAsync(userId, expectedName); + + //assert + Assert.That(count, Is.EqualTo(1)); + var user = users.Single(x => x.Id == userId); + Assert.That(expectedName, Is.EqualTo(user.FirstName)); + Assert.That(expectedName, Is.EqualTo(user.LastName)); + } + + [Test] + public async Task DbSetCreatedFromCollectionExecuteUpdateAsync_ShouldReturnZero() + { + // arrange + var userId = Guid.NewGuid(); + var users = TestDataHelper.CreateUserList(userId); + var arrangeUser = users.Single(x => x.Id == userId); + var expectedFirstName = arrangeUser.FirstName; + var expectedLastName = arrangeUser.LastName; + var mockDbSet = users.BuildMockDbSet(); + var userRepository = new TestDbSetRepository(mockDbSet); + + //act + var count = await userRepository.UpdateFirstAndLastNameByIdAsync(Guid.NewGuid(), "Unit Test"); + + //assert + Assert.That(count, Is.EqualTo(0)); + + var user = users.Single(x => x.Id == userId); + Assert.That(expectedFirstName, Is.EqualTo(user.FirstName)); + Assert.That(expectedLastName, Is.EqualTo(user.LastName)); } -} + + +} \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.Sample/SampleLikeExpressionVisitor.cs b/src/MockQueryable/MockQueryable.Sample/SampleLikeExpressionVisitor.cs new file mode 100644 index 0000000..87080bc --- /dev/null +++ b/src/MockQueryable/MockQueryable.Sample/SampleLikeExpressionVisitor.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq.Expressions; + +namespace MockQueryable.Sample; + +/// +/// This class rewrites ILike/Like method calls to simulate EntityFrameworkCore case-insensitive pattern matching in LINQ queries. +/// +public class SampleLikeExpressionVisitor : ExpressionVisitor +{ + private static readonly char[] Value = ['%']; + + /// + /// Rewrites the ILike method call to a string.Contains call with a trimmed + /// and lowercased pattern. + /// This is used to simulate the behavior of ILike/Like + /// + protected override Expression VisitMethodCall(MethodCallExpression node) + { + if (node.Method.Name is nameof(NpgsqlDbFunctionsExtensions.ILike) or nameof(DbFunctionsExtensions.Like) && + node.Arguments.Count == 3) + { + + var stringExpression = node.Arguments[1]; + var patternExpression = node.Arguments[2]; + + var toLowerPattern = Expression.Call(patternExpression, nameof(string.ToLower), Type.EmptyTypes); + var trimMethod = typeof(string).GetMethod(nameof(string.Trim), [typeof(char[])]); + var trimmedPattern = Expression.Call(toLowerPattern, trimMethod!, Expression.Constant(Value)); + + return Expression.Call( + Expression.Call(stringExpression, nameof(string.ToLower), Type.EmptyTypes), + nameof(string.Contains), + Type.EmptyTypes, + trimmedPattern + ); + } + + return base.VisitMethodCall(node); + } +} \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.Sample/TestDataHelper.cs b/src/MockQueryable/MockQueryable.Sample/TestDataHelper.cs new file mode 100644 index 0000000..2ab3cb2 --- /dev/null +++ b/src/MockQueryable/MockQueryable.Sample/TestDataHelper.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace MockQueryable.Sample; + +public static class TestDataHelper +{ + public static readonly CultureInfo UsCultureInfo = new("en-US"); + public static List CreateUserList(Guid? userId = null) => + [ + new() + { + Id = userId ?? Guid.NewGuid(), + FirstName = "FirstName1", LastName = "LastName1", + DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) + }, + + new() + { + Id = Guid.NewGuid(), + FirstName = "FirstName2", LastName = "LastName2", + DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) + }, + + new() + { + Id = Guid.NewGuid(), + FirstName = "FirstName3", LastName = "LastName4", + DateOfBirth = DateTime.Parse("01/20/2012", UsCultureInfo.DateTimeFormat) + }, + + new() + { + Id = Guid.NewGuid(), + FirstName = "FirstName3", LastName = "LastName4", + DateOfBirth = DateTime.Parse("03/20/2012", UsCultureInfo.DateTimeFormat) + }, + + new() + { + Id = Guid.NewGuid(), + FirstName = "FirstName5", LastName = "LastName4", + DateOfBirth = DateTime.Parse("01/20/2018", UsCultureInfo.DateTimeFormat) + } + + ]; +} \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.Sample/TestDbSetRepository.cs b/src/MockQueryable/MockQueryable.Sample/TestDbSetRepository.cs index 59266d0..eef78c4 100644 --- a/src/MockQueryable/MockQueryable.Sample/TestDbSetRepository.cs +++ b/src/MockQueryable/MockQueryable.Sample/TestDbSetRepository.cs @@ -1,35 +1,64 @@ using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace MockQueryable.Sample { - public class TestDbSetRepository : IUserRepository + public class TestDbSetRepository : IUserRepository + { + private readonly DbSet _dbSet; + + public TestDbSetRepository(DbSet dbSet) { - private readonly DbSet _dbSet; + _dbSet = dbSet; + } - public TestDbSetRepository(DbSet dbSet) - { - _dbSet = dbSet; - } - public IQueryable GetQueryable() - { - return _dbSet; - } + public IQueryable GetQueryable() + { + return _dbSet; + } - public async Task CreateUser(UserEntity user) - { - await _dbSet.AddAsync(user); - } + public async Task CreateUser(UserEntity user) + { + await _dbSet.AddAsync(user); + } - public async Task> GetAll() { - return await _dbSet.ToListAsync(); - } + public async Task> GetAll() + { + return await _dbSet.ToListAsync(); + } + + public IAsyncEnumerable GetAllAsync() + { + return _dbSet.AsAsyncEnumerable(); + } - public IAsyncEnumerable GetAllAsync() - { - return _dbSet.AsAsyncEnumerable(); - } + public async Task> GetUsersByFirstName(string firstName) + { + return await _dbSet + .Where(x => EF.Functions.Like(x.FirstName, $"%{firstName}%")) + .ToListAsync(); + } + + public async Task> GetUsersByLastName(string firstName) + { + return await _dbSet + .Where(x => EF.Functions.ILike(x.LastName, $"%{firstName}%")) + .ToListAsync(); + } + + public async Task DeleteUserAsync(Guid id) + { + return await _dbSet.Where(x => x.Id == id) + .ExecuteDeleteAsync(); + } + + public async Task UpdateFirstAndLastNameByIdAsync(Guid id, string firstName) + { + return await _dbSet.Where(x => x.Id == id) + .ExecuteUpdateAsync(opt => opt.SetProperty(x => x.FirstName, firstName).SetProperty(x => x.LastName, firstName)); } + } } \ No newline at end of file diff --git a/src/MockQueryable/MockQueryable.sln b/src/MockQueryable/MockQueryable.sln index 0c666c1..35c4ff4 100644 --- a/src/MockQueryable/MockQueryable.sln +++ b/src/MockQueryable/MockQueryable.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29102.190 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35931.197 d17.13 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.Core", "MockQueryable.Core\MockQueryable.Core.csproj", "{7C85327C-5EE5-4C74-A1E5-9B7046CA6CFE}" EndProject @@ -15,6 +15,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MockQueryable.FakeItEasy", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MockQueryable.EntityFrameworkCore", "MockQueryable.EntityFrameworkCore\MockQueryable.EntityFrameworkCore.csproj", "{E3632875-02A1-4C4A-96AB-62089D9D3F4F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + ..\..\.github\workflows\dotnetcore.yml = ..\..\.github\workflows\dotnetcore.yml + ..\..\LICENSE = ..\..\LICENSE + ..\..\README.md = ..\..\README.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU