romantitov / mockqueryable Goto Github PK
View Code? Open in Web Editor NEWMocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc
License: MIT License
Mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc
License: MIT License
I'm using a generic repository pattern that has an UpdateAsync method to update an entity in EF Core.
public async Task UpdateAsync(T entity)
{
context.Entry(entity).State = EntityState.Modified;
await context.SaveChangesAsync();
}
When I'm mocking the context using MockQueryable in a unit test, the call to the Entry method of the context returns null.
How should I mock the Entry method?
The Entry method returns an EntityEntry object; the constructor of EntityEntry is taking an InternalEntityEntry object that is internal to EF Core.
Here's my unit test using xUnit and Moq:
[Fact]
public async void UpdateAsync_SavesObject()
{
//Arrange
var persons = new List<Person>
{
new Person { Id = 1, FirstName = "Ken", MiddleName = "J", LastName = "Sánchez" },
new Person { Id = 2, FirstName = "Terri", MiddleName = "Lee", LastName = "Duffy" }
};
var mockSet = persons.AsQueryable().BuildMockDbSet();
var mockContext = new Mock<AWContext>();
mockContext.Setup(x => x.Set<Person>())
.Returns(mockSet.Object);
var repository = new EfRepository<Person>(mockContext.Object);
//Act
var existingPerson = new Person { Id = 1, FirstName = "Ken", MiddleName = "C", LastName = "Sánchez" };
await repository.UpdateAsync(existingPerson);
//Assert
mockContext.Verify(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()));
}
Consider two simple tests (xunit):
[Fact]
public async void CreateFoo_ShouldReturnNewlyCreatedFoo()
{
var mockSet = Mocks.FooListMock.AsQueryable().BuildMockDbSet();
var mockContext = new Mock<FooContext>(Options.Create(Mocks.CosmosDbMock));
mockContext.Setup(m => m.Foos).Returns(mockSet.Object);
Foos foosRepo = new Foos(mockContext.Object);
var result = await foosRepo.CreateFoo(MockedFooObject);
mockSet.Verify(m => m.Add(It.IsAny<Foo>()), Times.Once()); // <-- This works
mockContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
[Fact]
public async void DeleteFoo_WithValidId_ShouldReturnId()
{
var mockSet = Mocks.FooListMock.AsQueryable().BuildMockDbSet();
var mockContext = new Mock<FooContext>(Options.Create(Mocks.CosmosDbMock));
mockContext.Setup(m => m.Foos).Returns(mockSet.Object);
Foos foosRepo = new Foos(mockContext.Object);
var result = await foosRepo.DeleteFoo("id");
mockSet.Verify(m => m.Remove(It.IsAny<Foo>()), Times.Once()); // <-- This doesn't. It says it was called 0 times.
mockContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
Here are the methods under test:
public async Task<Foo> CreateFoo(Foo foo) {
_context.Foos.Add(foo);
await _context.SaveChangesAsync();
return foo;
}
public async Task<string?> DeleteFoo(string id) {
var foo = await _context.Foos.SingleOrDefaultAsync(p => p.FooId == id);
if (foo != null) {
_context.Foos.Remove(foo);
await _context.SaveChangesAsync();
return id;
} else {
return null;
}
}
Notice in the second test when verifying the Remove
method was called once, it fails saying it was called 0 times. However, if I comment that line out, the verify on the SaveChangesAsync
passes. What gives?
I've upgraded to the latest release to have the support for Entity Framework Core 3.0 but I receive the following error when running my unit tests:
System.MissingMethodException: Method not found: 'System.__Canon NSubstitute.Arg.Any()'.
Using NSubstitute version 4.2.1.
Running on macOS.
Part of the unit test code:
var myQueryableMock = myList.AsQueryable().BuildMock();
myRepositorySubstitute.Get(Arg.Any<Expression<Func<MyEntity, bool>>>()).Returns(myQueryableMock);
After having updated the MockQueryable package to version 6.0.0 some of my unit tests fail because .ToListAsync()
now returns an empty list.
Example code:
DbSet<Sections> mockSections = sections.AsQueryable().BuildMockDbSet();
_dbContext.Sections.Returns(mockSections);
List<Section> sections = await _dbContext.Sections.ToListAsync(cancellationToken);
The last line returns an empty list with the new package version. Why?
The failed tests and the full test code can be found here
Currently when mutating the base collection such that:
var userEntities = new List<UserEntity>();
var set = userEntities.AsQueryable().BuildMockDbSet()
userEntities.Add(new UserEntity());
set.Single();
results in the following exception:
System.InvalidOperationException : Collection was modified; enumeration operation may not execute.
It would be good to allow for mutation of the base enumerable when possible.
Consider:
var emails = new List<EmailQueueEntry>();
emails.Add(new EmailQueueEntry());
var mockSet = emails.AsQueryable().BuildMockDbSet();
emails.Add(new EmailQueueEntry());
var list= await mockSet.Object.ToListAsync();
This used to work fine in v5.0.1, but since upgrading our projects to .net6 and MockQueryable to 6.0.1 now throws System.InvalidOperationException : Collection was modified; enumeration operation may not execute
on the ToListAsync
call.
Seems to be a regression of this
Checked also with v7.0 does the same thing. I think it may be the method CreateAsyncMock
method in MoqExtensions.cs
added for v6.0.1 causing the issue.
I use BuildMockDbSet() method to create DbSet mock.
I have a simple class representing entity:
public class Feature {
[Key]
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
}
I see that FindAsync(Id) method is not working properly and returns null every time in spite of elements are existing and same predicate is working with EF DbContext. Have replaced with FirstOrDefault() for a while. Could you please take a look at this?
I have problem while mocking my repositories with query.
Repository Class Section:
public IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> filter)
{
return _dbContext.Set<TEntity>().Where(filter).AsQueryable();
}
Test Class Section:
...
var alarmRepositoryMock = new Mock<IAlarmRepository>();
var a1 = new Alarm
{
Code = 101,
Message = "Alarm!"
};
List<Alarm> alarms = new List<Alarm>();
alarms.Add(new Alarm
{
Id = new Guid(),
Code = a1.Code,
Message = a1.Message
});
var alarmsQueryable = alarms.AsQueryable().BuildMock();
alarmRepositoryMock.Setup(x => x.GetQuery(x => x.Code == 101)).Returns(alarmsQueryable.Object);
...
Service Class Section:
public async Task<string> AlarmAddOrUpdateAsync(AlarmDto model)
{
- var findAlarm = await _alarmRepository.GetQuery(x => x.Code == model.Code).FirstOrDefaultAsync();
...
}
When I update it as below, the problem disappears.
+ var findAlarm = await _alarmRepository.GetQuery(x => x.Code == 101).FirstOrDefaultAsync();
How can i parameterized this query. I want to be independent from Code value.
Any current plans to yet?
Trying the FakeItEasy flavour it in a .NET 5 RC2 project and seems to fail with:
System.IO.FileNotFoundException : Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
... which I install, but then it fails with:
Result Message: System.TypeLoadException : Could not load type 'Microsoft.EntityFrameworkCore.Query.Internal.IAsyncQueryProvider' from assembly 'Microsoft.EntityFrameworkCore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
Which I'm guessing might be a namespace difference between core 3.1 and 5 ?
code is var fakeQueryable = new List<Enquiry>().AsQueryable().BuildMock();
I saw it, similar has been discussed already, but it does still not work on my end
I have
var countries = CountryStub.GetCountries().AsQueryable().BuildMockDbSet(); // 3 items (1st is Id:1)
_uow.Setup(x => x.Context.Set<Country>()).Returns(countries.Object);
_uow.Setup(x => x.Context.Set<Country>().FindAsync(1)).ReturnsAsync(new Country { Id:1 }); // and I dont want to do this, collection contains that item already
var repository = new CountryRepository(_uow.Object);
var result = await repository.FindByIdAsync(1); //it calls FindAsync internally and result is null
and I would expect once I mock context Country that FindAsync method should return item with id:1
Hi I use this library and now I have encountered an issue, in one of my tests I need to trigger a class that behind the scene uses AddAsync to add the item I am passing in, then using the same context.dbset I am trying to get it but the dbset does not contain the element, only preexisting objects.
Is this scenario not supported?
Thank you
Do we already have this feature?
If no, I think this is necessery to make sure that Include
statement is called or not in my repository or query.
The sample scenario:
public class Lesson {
public int Id {get; set;}
}
public class Student {
public int Id {get; set;}
public List<Lesson> Lessons { get; set; }
}
var student1 = new Student(){
Id = 1,
Lessons = new List<Lesson>(){
new Lesson(){
Id = 1,
}
}
}
var students = new List<Student>(){
student1
};
var dataSetMock = students.AsQueryable().BuildMockDbSet();
var dbContextMock = new Mock<IDbContextInterface>();
dbContextMock.SetupGet(e => e.Students)
.Returns(dataSetMock.Object);
var repository = new StudentsRepository(dbContextMock.Object);
var studentResult = repository.GetById("12312312");
studentResult.Lessons.Should().NotBeNull();
But this will causes studentResult == student1
returns false
because we need to instansiate new object.
My suggestion for this, we can add new param in BuildMockDbSet
public static IQueryable<TEntity> BuildMock<TEntity>(this IQueryable<TEntity> data, bool loadNavigation= true) where TEntity : class {}
Thanks
:)
Describe the bug
Recently I've migrated my project to .net 5.0 with EF Core 5.0.
The BuildMock Extension now throws this error message:
System.TypeLoadException : Could not load type 'Microsoft.EntityFrameworkCore.Query.Internal.IAsyncQueryProvider' from assembly 'Microsoft.EntityFrameworkCore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
To Reproduce
Here is a small sniped of the code that throws the exception:
var users = (new[] { new User(), new User(), new User() }).AsQueryable().BuildMock();
Expected behavior
No exception generated. The mocked collection is created.
Environment:
Hello,
I am running into an issue where the ToListAsync() returns an empty list the second time it is called.
The issue can be easily reproduced by modifying one of the unit tests of your project,
adding a second call to the GetAll() function:
[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();
result = await userRepository.GetAll();
//assert
Assert.AreEqual(users.Count, result.Count);
}
I have updated my project from .NET core 3x to .NET 5, also updated Moq and MockQueryable for Moq and Im getting
System.InvalidOperationException : 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.
When I want to set a return value (null or none-null value) for FindOrDefaultAsync
method I get the following error:
Can not return value of type Task`1 for IQueryable.get_Expression (expected type Expression).
[Fact]
public async Task FindRole_WhenCall_ReturnsIdentityRole()
{
// Arrange
var iRole = new IdentityRole();
var dbset = new List<IdentityRole>()
{
new IdentityRole()
}
.AsQueryable().BuildMockDbSet();
dbset.FirstOrDefaultAsync(role => role.Name=="a")
.ReturnsNull();
_repository.Query().Returns(dbset);
// Act
var result = await _rolesService.FindRole("RoleName");
// Assert
result.Should().BeNull();
}
Hi Guys.
I use MockQueryable approach for EF async methods testing.
But I've noticed that it doesn't work for async methods for collections, exactly 'bulk extensions': https://entityframework-extensions.net/bulk-update
Message: System.AggregateException : One or more errors occurred. (Field '_queryCompiler' defined on type 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider' is not a field on the target object which is of type 'TestAsyncEnumerableEfCore[TEntity]'.) ---- System.ArgumentException : Field '_queryCompiler' defined on type 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider' is not a field on the target object which is of type 'TestAsyncEnumerableEfCore[TEntity]'.
After some investigation, I found out that Bulk extensions methods require using EntityQueryProvider as provider and IQueryCompiler as _queryCompiler field.
I use the next code to set up async EF methods for testing:
private Mock<DbSet<TEntity>> DbSetConfigureForAsync<TEntity>(Mock<DbSet<TEntity>> dbSet, IQueryable<TEntity> data)
where TEntity : class
{
var enumerable = new TestAsyncEnumerable<TEntity>(data);
// Configure queryable calls
dbSet.As<IQueryable<TEntity>>().Setup(m => m.Provider).Returns(enumerable);
dbSet.As<IQueryable<TEntity>>().Setup(m => m.Expression).Returns(data.Expression);
dbSet.As<IQueryable<TEntity>>().Setup(m => m.ElementType).Returns(data.ElementType);
dbSet.As<IQueryable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
// Configure async enumerable calls
dbSet.As<IAsyncEnumerable<TEntity>>()
.Setup(m => m.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
.Returns(enumerable?.GetAsyncEnumerator());
// Configure DbSet calls
dbSet.Setup(m => m.AsQueryable()).Returns(enumerable); // alternative: _mockSet.Object
dbSet.Setup(m => m.AsAsyncEnumerable()).Returns(CreateAsyncMock(data));
return dbSet;
}
Thanks.
This issue is related to #32 but there was no resolution given there so I am opening a new issue.
When mocking an IQueryable, I am getting the exception
System.InvalidOperationException : The source IQueryable doesn't implement IAsyncEnumerable<Event>. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
My code is structured as follows:
// Method Under Test
public async Task<List<Event>> GetEvents(FilterOptions filterOptions)
{
var queryable = GetEventsQueryable();
queryable = FilterByDate(queryable, filterOptions);
// queryable = FilterByLocation(), FilterBy...(), etc
var events = await queryable
.ToListAsync()
.ConfigureAwait(false);
return events;
}
public IQueryable<Event> GetEventQueryable()
{
try
{
return MyDbContext
.EventData
.AsQueryable();
}
catch
{
...
}
}
public IQueryable<Event> FilterByDate(
IQueryable<Event> queryable,
FilterOptions options)
{
if (options.StartDate != null)
{
queryable = queryable.Where(e => e.EventDate >= options.StartDate);
}
if (options.EndDate != null)
{
queryable = queryable = queryable.Where(e => e.EventDate <= options.EndDate);
}
return queryable;
}
// Test
private List<Event> Events
{
get
{
new List<Event>
{
...
};
}
}
[Fact]
public void GetEvents_DefaultFilterOptions_ReturnsAllEvents()
{
// Arrange
var mockQueryable = Events.AsQueryable().BuildMock();
var expectedEvents = new List<Event>
{
...
};
...
mockCaller
.Setup(m => m.GetEventsQueryable())
.Returns(mockQueryable);
mockCaller
.Setup(m => m.FilterByDate(It.IsAny<IQueryable<Event>>(), It.IsAny<FilterOptions>()))
.Returns(mockQueryable);
var eventManager = new EventManager();
var filterOptions = new EventFilterOptions();
// Act
var actualEvents = eventManager.GetEvents(filterOptions);
// Assert
Assert.Equal(expectedEvents, actualEvents);
}
When the test gets to the events = await queryable.ToListAsync()
line it throws the System.InvalidOperationException.
I am not sure what is going wrong or how to fix the issue. I started looking into using the TestAsyncEnumerableEfCore class and trying to return this instead of the mocked queryable, but the issue still persisted.
Using EntityFrameworkCore 3.0.0-preview7.19362.6 The IAsyncEnumerable
IAsyncQueryProvider
and IAsyncEnumerator
interfaces require different members.
As far as I can tell the member changes are as follows:
IAsyncEnumerable
:
GetAsyncEnumerator(CancellationToken)
IAsyncQueryProvider
:
ExecuteAsync<TResult>(Expression, CancellationToken)
with return type of TResult
IAsyncEnumerator
:
MoveNextAsync()
IAsyncDisposable
:
DisposeAsync()
As far as I can tell, the ExecuteAsync()
methods that return IAsyncEnumerable
or Task<TResult>
are unnecessary now.
These interface changes also appear to break some of the non-core packages as well, apparrently due to the removal of the GetEnumerator
method on IAsyncEnumerable
(I believe this just needs to be changed to GetAsyncEnumerator
instead)
related GitHub issue:
dotnet/efcore#12047
Mocking an IAsyncEnumerable
result from a DbSet
using NSubstitute does not work and instead yield an empty result set.
A fix for this exact same issue was adressed in #25 but only for the Moq library.
Same override should be applied when using NSubstitute.
The following code snipped should return all users from a DbSet
List<UserEntity> users = new List<UserEntity> { new UserEntity() };
DbSet<UserEntity> mockDbSet = users.AsQueryable().BuildMockDbSet();
dbContext.Users.Returns(mockDbSet);
List<UserEntity> result = await userRepository.GetAllUsersAsync().ToListAsync(cancellationToken);
Assert.AreEqual(users.Count, result.Count);
Instead, an empty collection is returned.
_mockContext = new Mock<ApplicationDbContext>(options);
var data = items.AsQueryable();
var mockSet = data.BuildMockDbSet();
mockSet.Setup(x => x.FirstOrDefaultAsync(It.IsAny<System.Linq.Expressions.Expression<Func<Notes, bool>>>(), It.IsAny<System.Threading.CancellationToken>())).ReturnsAsync((object pred) =>
{
var predicate = (System.Linq.Expressions.Expression<Func<Notes, bool>>)pred;
var r = (Notes)data.FirstOrDefault(pred);
return r;
});
mockSet.Setup(x => x.GetQueryable()).Returns(mockSet.Object);
_mockContext.Setup(m => m.Notes).Returns(mockSet.Object);
This package looks useful. Unfortunately however, it doesn't solve the problem of calling async methods on IQueryable
objects.
For example, calling .ToListAsync() on my mock queryable still throws:
System.InvalidOperationException : The source IQueryable doesn't implement IAsyncEnumerable<MyClass>. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
public class ApplicationControllerTests
{
private static IEnumerable<Application> GetApplications() => new[]
{
new Application
{
...
},
...
};
[Fact]
public async Task GetApplicationsReturnsExpected()
{
//Arrange
var applications = GetApplications()
.AsQueryable()
.BuildMock();
var fixture = ApplicationControllerFixture.Create();
fixture.QueryService
.Setup(s => s.GetApplications())
.Returns(applications.Object);
//Act
var result = await fixture.Controller.GetApplications();
//Assert
var response = Assert.IsType<OkObjectResult>(result);
}
}
[ApiController]
public class ApplicationController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetApplications()
{
LogActivity(nameof(GetApplications), Request);
var list = await QueryService.GetApplications(ClientId)
.ToListAsync();
return Ok(list);
}
}
Tried upgrading to .net5.0 preview6 .
I get the following error: System.IO.FileNotFoundException : Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
After Installing Microsoft.Bcl.AsyncInterfaces from Nuget I get:
System.TypeLoadException : Could not load type 'Microsoft.EntityFrameworkCore.Query.Internal.IAsyncQueryProvider' from assembly 'Microsoft.EntityFrameworkCore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
For simple usage with no customization to the IQueryable<T>
mock (such as the "How do I get started" example in the readme) there is no need for a mocking framework to be involved. Using TestAsyncEnumerableEfCore<T>
directly is almost 1000x faster which was a very easy performance win for me :). My small test suite is about 15% faster now.
This issue is to request documenting TestAsyncEnumerableEfCore<T>
in the readme. I would be happy to write it and submit a PR if that would be acceptable.
Thank you for this package!
Here's the benchmark I used and its results:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using MockQueryable.EntityFrameworkCore;
using MockQueryable.Moq;
BenchmarkRunner.Run(typeof(Program).Assembly);
[MemoryDiagnoser]
public class InitializeInstance
{
private readonly IEnumerable<string> _input;
public InitializeInstance()
{
_input = new[] { "1", "2", "3" };
}
[Benchmark(Baseline = true)]
public IList<string> Moq()
{
var mock = _input.AsQueryable().BuildMock();
return mock.Object.ToList();
}
[Benchmark]
public IList<string> NoMoq()
{
return new TestAsyncEnumerableEfCore<string>(_input).ToList();
}
}
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
Intel Core i9-9900 CPU 3.10GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.201
[Host] : .NET 6.0.3 (6.0.322.12309), X64 RyuJIT
DefaultJob : .NET 6.0.3 (6.0.322.12309), X64 RyuJIT
Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Allocated |
---|---|---|---|---|---|---|---|
Moq | 69,971.94 ns | 670.265 ns | 594.172 ns | 1.000 | 2.0752 | 0.9766 | 17,951 B |
NoMoq | 70.09 ns | 0.647 ns | 0.605 ns | 0.001 | 0.0248 | - | 208 B |
Is there any chance that you can support the most common EF functions like EF.Functions.Like
?
An relatively simple approach might be to write an ExpressionVisitor that replace those function calls with mock functions.
I think it would generally be a great idea to add an optional Visitor
property to TestAsyncEnumerableEfCore<T>
where you can pass a custom visitor that is used instead of the new TestExpressionVisitor()
. This would allow developers to mock all sorts of custom functions and the like.
I would really appreciate this feature.
Is it possible to get this package created with a strong name?
Protip: When supporting EF Core 3.1, mocked DbSet<>
objects need to additionally override the newly-added methods .AsQueryable()
and .AsAsyncEnumerable()
(which simply return this;
) within BuildMockDbSet()
calls.
Anyone who (like me) was using the .AsQueryable()
extension method upon a DbSet<>
in production code will, after upgrade to 3.1, be calling the methods upon DbSet<>
instead. In my case, this meant that instead of getting a cast of the DbSet<>
to IQueryable<>
I was getting an auto-generated default implementation from Moq's DefaultValueProvider
, which is basically Array.Empty<T>.AsQueryable()
.
AutoMapper casts an IQueryable to IQueryable which breaks the current implementation of CreateQuery in the TestAsyncEnumerable class. I have got this working by adding the following into the public IQueryable CreateQuery(Expression expression) method:
public IQueryable CreateQuery(Expression expression)
{
if (expression is MethodCallExpression m)
{
var resultType = m.Method.ReturnType; // it shoud be IQueryable<T>
var tElement = resultType.GetGenericArguments()[0];
var queryType = typeof(TestAsyncEnumerable<>).MakeGenericType(tElement);
return (IQueryable)Activator.CreateInstance(queryType, expression);
}
return new TestAsyncEnumerable<T>(expression);
}
Hello!
I've been using MockQueryable with .NET6 a lot
Recently my project migrated to .NET 7 (EF Core 7)
And I started to use new EF7 features:
...
.Where(user => user.Id == id)
.ExecuteDeleteAsync();
ExecuteDeleteAsync implementation is here
https://github.com/dotnet/efcore/blob/main/src/EFCore.Relational/Extensions/RelationalQueryableExtensions.cs#L316
.Where(user => user.Id == id)
.ExecuteUpdateAsync(updater => updater
.SetProperty(
user => user.Status,
user => status)
.SetProperty(
user => user.ModifiedBy,
user => _userContextProvider.GetUserId())
.SetProperty(
user => user.ModifiedOn,
user => DateTimeOffset.UtcNow));
ExecuteUpdateAsync implementation is here
https://github.com/dotnet/efcore/blob/main/src/EFCore.Relational/Extensions/RelationalQueryableExtensions.cs#L372
I use MockQueryable using a standard pattern:
var mock = users.BuildMock();
_userRepository.Setup(x => x.GetQueryable()).Returns(mock);
ToListAsync(), FirstOrDefaultAsync() and others works perfectly with this pattern.
Unfortunately ExecuteUpdateAsync / ExecuteDeleteAsync doesn't work at all :(
When I try to run a unit test, a mocked GetQueryable
method works nicely as usual, but it throws an exception on ExecuteDeleteAsync
<System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.InvalidOperationException: There is no method 'ExecuteDelete' on type 'Microsoft.EntityFrameworkCore.RelationalQueryableExtensions' that matches the specified arguments
at System.Linq.EnumerableRewriter.FindMethod(Type type, String name, ReadOnlyCollection`1 args, Type[] typeArgs)
at System.Linq.EnumerableRewriter.VisitMethodCall(MethodCallExpression m)
at System.Linq.EnumerableExecutor`1.Execute()
at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[TElement](Expression expression)
at Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.ExecuteDelete[TSource](IQueryable`1 source)
at lambda_method34(Closure)
at MockQueryable.Core.TestQueryProvider`1.CompileExpressionItem[TResult](Expression expression)
at MockQueryable.Core.TestQueryProvider`1.Execute[TResult](Expression expression)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
--- End of inner exception stack trace ---
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at MockQueryable.EntityFrameworkCore.TestAsyncEnumerableEfCore`1.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.ExecuteDeleteAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
Exception throws here on .Invoke(this, new object[] { expression });
https://github.com/romantitov/MockQueryable/blob/master/src/MockQueryable/MockQueryable.EntityFrameworkCore/TestQueryProviderEfCore.cs#L25
Same exception throws at ExecuteUpdateAsync (but it says There is no method 'ExecuteUpdate' on type 'Microsoft.EntityFrameworkCore.RelationalQueryableExtensions' that matches the specified arguments
)
The custom logic
pattern doesn't work because ExecuteUpdateAsync / ExecuteDeleteAsync are IQueryable extensions
Thank you very much
I need to mock AddAsync(obj)
function.
I have seen this stackoverflow topic, but proposed code:
mockWebJobDbSet
.Setup(_ => _.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>()))
.Callback((WebJobStatus model, CancellationToken token) => { webjobstatusList.Add(model); })
.Returns((WebJobStatus model, CancellationToken token) => Task.FromResult((EntityEntry<WebJobStatus>)null));
will return null EntityEntry<WebJobStatus>
which will cause to fail my unit test.
Function I want to test:
Url obj = new()
{
FullUrl = url
};
var savedObj = await _context.Url.AddAsync(obj);
return savedObj.Entity.Id
Error: savedObj
is null
I'm trying to mock the SingleOrDefaultAsync method with FakeItEasy but I get the error:
"FakeItEasy0002: Member SingleOrDefaultAsync can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted."
Here is the my code:
var claimants = fixture.CreateMany<Claimant>();
var claimantsDbSet = claimants.AsQueryable().BuildMockDbSet();
A.CallTo(() => claimantsDbSet.SingleOrDefaultAsync(A<Expression<Func<Claimant, bool>>>.Ignored, A<CancellationToken>.Ignored))
.Returns(claimant);
Is this not possible with FakeItEasy?
Hi
I'm using the MockQueryable.Core 3.0.1
I'm trying to a CountAsync on TestAsyncEnumerable and get a Value cannot be null. (Parameter 'arg0')
Normal enumeration does work.
I've included a sample
Hi,
When I try to use BuildMock().Object with an empty list, I've got the following exception. In my case, I use ToListAsync() method of EF Core.
System.InvalidOperationException: The source 'IQueryable' doesn't implement 'IAsyncEnumerable<Kazandirio.CampaignRepository.Model.Campaign>'. Only sou...
_campaignUnitOfWorkMock.Setup(a => a.GetQueryable<Campaign>()) .Returns(() => new List<Campaign>().AsQueryable().BuildMock().Object);
What license are you planning to use for this code? The project I would like to use this nuget package in has some restrictions about what types of licenses we can use. Thanks.
In dotnet/efcore#20294 the client side implementations of EF.Functions methods (eg EF.Functions.Like) were removed which broke any unit tests using them with mockqueryable data.
Hi, is there a way to have a dbSetMock with a composite primary key?
In my test i use
mockContext.Verify(_ => _.SaveChangesAsync(), Times.Once());
to verify that SaveChangesAsync() is called
in the function i test. I check if the SaveChanges call is successful by its result
int results = await _context.SaveChangesAsync(CancellationToken.None);
if (results >= 1)
{
return new OkObjectResult();
}
return new BadRequestObjectResult();
While testing my function fails as SaveChangesAsync always returns 0;
I'm i doing something wrong? or is This a Bug?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.