How to arrange a ReturnsCollection that is AsyncEnumerable

0 Answers 333 Views
Async Mocking
Edward
Top achievements
Rank 1
Edward asked on 05 Jun 2023, 02:49 PM

I have a test case to test my EF repository getallasync call as follows:

// Arrange
var systemsData = new List<SystemEntity>
{
new SystemEntity { SystemId = 1, Full_Year_Standings = true, Season_StartDate = DateTime.Now, Season_EndDate = DateTime.Now },
new SystemEntity { SystemId = 2, Full_Year_Standings = false, Season_StartDate = DateTime.Now, Season_EndDate = DateTime.Now },
new SystemEntity { SystemId = 3, Full_Year_Standings = true, Season_StartDate = DateTime.Now, Season_EndDate = DateTime.Now }
};

var mockContext = Mock.Create<BetCenterContext>(Behavior.Loose);
Mock.Arrange(() => mockContext.Set<SystemEntity>()).ReturnsCollection(systemsData);

var systemRepository = new SystemRepository(mockContext);

// Act
var result = await systemRepository.GetAllAsync();

 

Calling the following method:

 

public async Task<List<SystemEntity>> GetAllAsync()
{
var collToReturn = await _context.Set<SystemEntity>().ToListAsync();

return collToReturn;
}

The arranged mock returns a null result and throws InvalidOperationException - The source 'IQueryable' doesn't IAsyncEnumerable...'

How do I arrange the mock to return the correct value?

     
Edward
Top achievements
Rank 1
commented on 07 Jun 2023, 03:48 PM

Since the initial question I have learned a few different ways to convert my test data to a IAsyncEnumerable.  Among them writing a static method that yields the test data.  Also using the ToAsyncEnumerable method call in System.Linq.Async library.  Both give me the test object I want.

The problem now is that there doesn't seem to be any way to return the  IAsyncEnumerable test object in the Telerik Mock.Arrange methods. ReturnsCollection throws a compile error, as does Returns (which isn't a fit but I tried it anyways).

Any ideas?

Ivo
Telerik team
commented on 08 Jun 2023, 12:32 PM | edited

With little help from the extension methods like the following you can achieve the desired conversion, here is the code:

public static class IEnumeratorExtension
{
    public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerator<T> iterator)
    {
        while (iterator.MoveNext())
        {
            await Task.Yield();
            yield return iterator.Current;
        }
    }

    public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerator iterator)
    {
        while (iterator.MoveNext())
        {
            await Task.Yield();
            yield return (T)iterator.Current;
        }
    }
}
You will need aslo to change the arrangement in the test like that:
Mock.Arrange(() => mockContext.Set<SystemEntity>()).Returns(systemsData.GetEnumerator().ToAsyncEnumerable<SystemEntity>());

No answers yet. Maybe you can help?

Tags
Async Mocking
Asked by
Edward
Top achievements
Rank 1
Share this question
or