Search code examples
c#azure-table-storagefakeiteasyiasyncenumerable

Using FakeItEasy to fake an AsyncPageable


I've run into a problem while testing an Azure Function which runs on top of Azure Tables: How can I fake the result of a table query which returns an AsyncPageable?

Here's the code under test...

public async Task<Project?> GetProjectByIdAsync(Guid projectId)
{
    const int maxResultsPerPage = 1;
    IEnumerable<string>? selectProps = null;

    // _projectsTableService is an ITableService.
    var tableClient = _projectsTableService.GetTableClient();

    var results = tableClient.QueryAsync<Project>(project => project.Id.Equals(projectId),
                                                  maxResultsPerPage,
                                                  selectProps,
                                                  CancellationToken.None);

    await foreach (var result in results)
    {
        return result;
    }

    return null;
}

And here's my work-in-progress test method...

[TestInitialize]
public void TestInit()
{
    _project = new Project { Id = Guid.NewGuid() };
    _tableClient = A.Fake<TableClient>();
    _tableService = A.Fake<ITableService>();
    _tableServiceFactory = A.Fake<ITableServiceFactory>();

    A.CallTo(() => _tableService.GetTableClient()).Returns(_tableClient);
    A.CallTo(() => _tableServiceFactory.Create(TableName)).Returns(_tableService);

    _testee = new ProjectsTableService(_tableServiceFactory);
}

[TestMethod]
public async Task GetProjectByIdAsync_WhenMatchingProjectFound_ReturnsProject()
{
    var projectId = Guid.NewGuid();
    var project = new Project { Id = projectId };
    var projectsResult = new List<Project> { _project };
    var asyncPageable = A.Fake<AsyncPageable<Project>>();
    var enumerator = projectsResult.ToAsyncEnumerable().GetAsyncEnumerator();

    A.CallTo(() => asyncPageable.GetAsyncEnumerator(A<CancellationToken>._)).Returns(enumerator);

    A.CallTo(() => _tableClient.QueryAsync(A<Expression<Func<Project, bool>>>._,
                                           A<int>._,
                                           A<IEnumerable<string>>._,
                                           A<CancellationToken>._)).Returns(asyncPageable);

    var result = await _testee.GetProjectByIdAsync(_project.Id);

    result.Should().NotBeNull();
    result.Id.Should().Be(projectId);
}

When I step through this test the results AsyncPageable<Project> contains no results.


UPDATE
Here's a second attempt based on this example...

[TestMethod]
public async Task GetProjectByIdAsync_WhenMatchingProjectFound_ReturnsProject2()
{
    var projectId = Guid.NewGuid();
    var project = new Project { Id = projectId };
    var projects = new List<Project> { _project };
    var page = Page<Project>.FromValues(projects,
                                        continuationToken: null,
                                        response: A.Fake<Response>());
    var pages = AsyncPageable<Project>.FromPages(new[] { page });

    A.CallTo(() => _tableClient.QueryAsync(A<Expression<Func<Project, bool>>>._,
                                           A<int>._,
                                           A<IEnumerable<string>>._,
                                           A<CancellationToken>._)).Returns(pages);

    var result = await _testee.GetProjectByIdAsync(_project.Id);

    result.Should().NotBeNull();
    result.Id.Should().Be(projectId);
}

Can anyone help me to fake this AsyncPageable result?


Solution

  • I found out the cause of my problem: As @BlairConrad alluded to in his comment, it was in my initial set-up of the dependencies...

    A.CallTo(() => _tableServiceFactory.Create(TableName)).Returns(_tableService);
    

    The TableName member differs between my test class and the implementation. I'm still not sure why I was getting any faked objects, but that's a secondary question.

    So I now have a working test using code found in the post lined by @PeterBons', which is shown in the update in the OP.