Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async methods missing for FakeContext? #673

Closed
slee-accesso opened this issue Mar 17, 2021 · 6 comments
Closed

Async methods missing for FakeContext? #673

slee-accesso opened this issue Mar 17, 2021 · 6 comments
Assignees
Labels

Comments

@slee-accesso
Copy link

I've been trying to use the FakeDbContext, and it fails anytime I try to run async methods. The synchronous methods work - and the async methods do work against the "real" context, just not against the fake one.

Is there a setting I'm missing? Or is the generation code skipping the async methods? Here's the sample code I'm using in a unit test:

var factory = new Project.Data.Context.FakeProjectContextFactory();
var context = factory.CreateDbContext();
var c1 = context.Contacts.FirstOrDefault();    // succeeds (get a null back)
var c2 = await context.Contacts.FirstOrDefaultAsync();  // Dies a horrible death. Exception below.

Exception:

System.ArgumentException
Argument expression is not valid
   at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[TElement](Expression expression)
   at Project.Data.Context.FakeDbAsyncQueryProvider`1.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken) in C:\Dev\Project\Project.Data\Project.Data.Context\GeneratedCode\FakeDbSet.cs:line 239
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at UnitTests.ContextFactoryTests.FakeContextFactory_AddTwoContactsAsync_EnsureTheyWereAdded() in C:\Dev\Project\Project.Data\UnitTests\FactoryTests.cs:line 78
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_0(Object state)
   at Xunit.Sdk.AsyncTestSyncContext.<>c__DisplayClass7_0.<Post>b__1(Object _) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\AsyncTestSyncContext.cs:line 75

This occurs for every async method I've tried (AddRangeAsync, query.ToArrayAsync(), query.ToListAsync(), etc.)

And help would be much appreciated! Thanks!

  • Sean
@sjh37 sjh37 self-assigned this Mar 17, 2021
@sjh37
Copy link
Owner

sjh37 commented Mar 17, 2021

In the generated code, change one function within public class FakeDbAsyncQueryProvider<TEntity> : IAsyncQueryProvider to be:

public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = new CancellationToken())
{
    var expectedResultType = typeof(TResult).GetGenericArguments()[0];
    var executionResult = typeof(IQueryProvider)
        .GetMethod(
            name: nameof(IQueryProvider.Execute),
            genericParameterCount: 1,
            types: new[] { typeof(Expression) })
        .MakeGenericMethod(expectedResultType)
        .Invoke(this, new[] { expression });

    return (TResult) typeof(Task).GetMethod(nameof(Task.FromResult))
        ?.MakeGenericMethod(expectedResultType)
        .Invoke(null, new[] { executionResult });
}

Let me know if that works for you. In the mean time I will implement this in the generator.

@sjh37
Copy link
Owner

sjh37 commented Mar 17, 2021

See changeset f0a8589

Grab the latest code for EF.Reverse.POCO.v3.ttinclude and update your project.

@sjh37
Copy link
Owner

sjh37 commented Mar 17, 2021

Let me know if this does not work, and I will re-open this case.

@sjh37 sjh37 closed this as completed Mar 17, 2021
@slee-accesso
Copy link
Author

Simon - thanks for such a quick response!

Your fix took care of 3 of my test cases, but one still fails - AddRangeAsync(). FirstOrDefaultAsync(), ToArrayAsync() and ToListAsync() all now work as expected. Here's the code for the failing AddRangeAsync() test:

[Fact]
public async void FakeContextFactory_AddFourContactsWithAddRangeAsync_EnsureTheyWereAdded()
{
    var list1 = new List<Contact>
    {
        new Contact { FirstName = "TestOne", LastName = "Test", ContactId = 1},
        new Contact { FirstName = "TestTwo", LastName = "Test", ContactId = 2}
    };
    var list2 = new List<Contact>
    {
        new Contact { FirstName = "TestThree", LastName = "Test", ContactId = 3},
        new Contact { FirstName = "TestFour", LastName = "Test", ContactId = 4}
    };
    var factory = new Project.Data.V5.Context.FakeProjectContextFactory();
    var context = factory.CreateDbContext();
    context.Contacts.AddRange(list1);            // This works fine
    await context.Contacts.AddRangeAsync(list2); // Crashes - exception below...
    Assert.Equal(4, context.Contacts.Count());
}

Exception:

System.NotImplementedException
The method or operation is not implemented.
   at Microsoft.EntityFrameworkCore.DbSet`1.AddRangeAsync(IEnumerable`1 entities, CancellationToken cancellationToken)
   at UnitTests.ContextFactoryTests.FakeContextFactory_AddFourContactsWithAddRangeAsync_EnsureTheyWereAdded() in C:\Dev\Project\Project.Data\UnitTests\ContextFactoryTests.cs:line 83
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_0(Object state)
   at Xunit.Sdk.AsyncTestSyncContext.<>c__DisplayClass7_0.<Post>b__1(Object _) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\AsyncTestSyncContext.cs:line 75

@sjh37
Copy link
Owner

sjh37 commented Jun 9, 2021

@slee-accesso This is now fixed and will be in the next release.

@sjh37 sjh37 closed this as completed Jun 9, 2021
@sjh37
Copy link
Owner

sjh37 commented Jun 23, 2021

Released in v3.4.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants