I am working with xunit and moq.
I am trying to test FindAsyncTestAsync
method return something (not null) using xUnit and Moq.
I have instantiated all the required mock repository instances using constructor.
I have also instantiated the ParticipantService
in the test method.
[Fact]
public async Task FindAsyncTestAsync()
{
var participantList = ParticipantMockData.ListAllAsyncEntity(); // not null. length is 2
_participantRepository.Setup(_ => _.FindAsync(new Guid("ffbf486f-bf31-4bb4-8fc2-5beaae59e127")))
.Returns(Task.FromResult(participantList[0])); // soemthing is wrong here. I don't know
var sut = new ParticipantService(
_participantRepository.Object,
_participantSupportNeed.Object,
_participantConnection.Object,
_participantDisability.Object,
_participantMedicalCondition.Object,
_supportNeed.Object,
_disabilityn.Object,
_medicalCodition.Object,
_participantApplicationUser.Object,
_appLogger.Object);
var result = await sut.FindAsync(new Guid("ffbf486f-bf31-4bb4-8fc2-5beaae59e127"));
Assert.NotNull(result);
Assert.Equal(participantList[0].Id, result?.Id);
}
Test respond is:
Message:
System.Exception : The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations.
IRepository.cs
public interface IRepository<E> where E : IEntityBase
{
Task<List<E>> ListAsync(bool withInactives = false);
IQueryable<E> AsNoTracking(bool withInactives = false);
Task<E?> FindAsync(params object[] keyValues);
}
FindAsync method in ParticipantService
public async Task<ParticipantAsyncModel?> FindAsync(Guid id)
{
try
{
var participant = await participantRepository.AsNoTracking()
.Where(a => a.Id == id)
.Include(a => a.ParticipantAddresses)
.Include(a => a.ParticipantConnections)!.ThenInclude(a => a.Connection)
.Include(a => a.ParticipantApplicationUsers)!.ThenInclude(a => a.ApplicationUser)
.FirstOrDefaultAsync();
var participantView =
new ParticipantAsyncModel()
{
// object removed for simplistic
};
if (participantView is null) return null;
var participantModel = participantView.Adapt<ParticipantAsyncModel>();
return participantModel;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
Can anyone help me to find the problem.
CodePudding user response:
// soemthing is wrong here. I don't know
Nothing is with the setup per ce, it will work for IRepository.FindAsync
call just fine, the problem here is that you are not invoking this method in ParticipantService.FindAsync
, you are invoking IRepository.AsNoTracking
which obviously was not setup correctly. As a quick fix you can use EF Core in-memory database to return from IRepository.AsNoTracking
mock, but I would say you should reconsider the whole solution design.
There are quite a lot of developers which consider using (generic) repository over EF as antipattern (for example cause EF is already implementing repository pattern, as well as Unit Of Work), but even if you are not ready to make such drastic design changes, you should consider scrapping method returning IQueryable
from the repository due to the "leaky abstraction" created here - clients (like ParticipantService
in FindAsync
) rely on the IQueryable
returned from the method to be EF Core IQueryable
(or something which supports all EF Core extension methods like AsNoTracking
, Include
, etc., see EntityFrameworkQueryableExtensions
), which is why you have the exception in question.
CodePudding user response:
Mocking AsNoTracking is working for me.
//1 - create a List<T> with test items
var participantList = ParticipantMockData.ListAllAsyncEntity();
//2 - build mock by extension
var mock = participantList.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_participantRepository.Setup(x => x.AsNoTracking(false)).Returns(mock);
var sut = new ParticipantService(
_participantRepository.Object, _participantSupportNeed.Object, _participantConnection.Object, _participantDisability.Object, _participantMedicalCondition.Object, _supportNeed.Object, _disability.Object, _medicalCondition.Object, _participantApplicationUser.Object, _appLogger.Object);
var result = await sut.FindAsync(new Guid("ffbf486f-bf31-4bb4-8fc2-5beaae59e127"));