0

I tried to write test case for my DataAccess method containing QueryMultipleAsync but it being failed showing the error :

Error : Message:  System.NotSupportedException : Unsupported expression: gr => gr.ReadAsync(It.IsAny()) Non-overridable members (here: SqlMapper.GridReader.ReadAsync) may not be used in setup / verification expressions.

so here is my DataAccess method where I have used QueryMultipleAsync. :

public async Task<bool> SummerData(Guid darkStoreId, Guid storeId, long id)
{
    await _context.OpenConnectionForKeyAsync(darkStoreId);
    var result= await _context.Connection.QueryMultipleAsync(_checkMappingStatus, new { storeId, id });
    return await DataStocks(result);
}

so for this I have tried to write a test case :

        [Fact]
        public async Task SummerData()
        {

            var expectedResult = new List<object> { new { id = 1L, tenantClientId = tenantClientId } };
            QueryMultiAsync(expectedResult);

            sampleDataAccess.Setup(s => s.VerifySampleExistAsync(tenantId, tenantClientId, 1)).ReturnsAsync(false);
            await data.VerifySampleExistAsync(tenantId, tenantClientId, 1);

            string Name = "Test";

            Assert.True(Name == classs.Name);
        }

so there i have tried to mock the QueryMultiAsync

 public object DataStocks(IEnumerable<dynamic> expected)
 {
     var mockGridReader = new Mock<GridReader>();

     mockGridReader.Setup(a => a.ReadAsync(It.IsAny<Type>(), It.IsAny<bool>()))
         .Returns<Type, bool>((type, buffered) => Task.FromResult(expected));


     _iConnection.SetupDapperAsync(c => c.QueryMultipleAsync(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<int?>(), It.IsAny<CommandType?>()))
         .ReturnsAsync(mockGridReader.Object);


     this._dbService.Setup(x => x.Connection).Returns(_iConnection.Object);
     this._dbCatalogue.Setup(x => x.Connection).Returns(_connection.Object);
     this._dbTransaction.Setup(x => x.Connection).Returns(_connection.Object);

     return expected;
 }

So this was the code. Now on running the test case it get stuck in this line :

mockGridReader.Setup(a => a.ReadAsync(It.IsAny<Type>(), It.IsAny<bool>()))
         .Returns<Type, bool>((type, buffered) => Task.FromResult(expected));

Please If anyone knows how to fix this or write test case for this. Thank You!

1
  • 1
    Dapper maintainer here: ultimately ADO.NET is not a very mockable layer, and honestly: I struggle to see what value you're adding in this test - IMO either mock an abstraction that encapsulates the data access, or do an integration test against a meaningful database (ideally the one you're actually using). Commented Feb 6 at 10:18

1 Answer 1

0

Create a wrapper class around the GridReader and mock the wrapper instead. This allows you to control the behavior of the ReadAsync method.

public interface IGridReaderWrapper
{
    Task<IEnumerable<dynamic>> ReadAsync(Type type, bool buffered);
}

public class GridReaderWrapper : IGridReaderWrapper
{
    private readonly SqlMapper.GridReader _gridReader;

    public GridReaderWrapper(SqlMapper.GridReader gridReader)
    {
        _gridReader = gridReader;
    }

    public Task<IEnumerable<dynamic>> ReadAsync(Type type, bool buffered)
    {
        return _gridReader.ReadAsync(type, buffered);
    }
}

Then, modify your QueryMultiAsync method to use the wrapper:

public object QueryMultiAsync(IEnumerable<dynamic> expected)
{
    var mockGridReaderWrapper = new Mock<IGridReaderWrapper>();

    mockGridReaderWrapper.Setup(a => a.ReadAsync(It.IsAny<Type>(), It.IsAny<bool>()))
        .Returns<Type, bool>((type, buffered) => Task.FromResult(expected));

    var mockGridReader = new Mock<SqlMapper.GridReader>();
    var gridReaderWrapper = new GridReaderWrapper(mockGridReader.Object);

    _iConnection.SetupDapperAsync(c => c.QueryMultipleAsync(It.IsAny<string>(), It.IsAny<object>(), It.IsAny<IDbTransaction>(), It.IsAny<int?>(), It.IsAny<CommandType?>()))
        .ReturnsAsync(gridReaderWrapper);

    this._dbService.Setup(x => x.Connection).Returns(_iConnection.Object);
    this._dbCatalogue.Setup(x => x.Connection).Returns(_connection.Object);
    this._dbTransaction.Setup(x => x.Connection).Returns(_connection.Object);

    return expected;
}

Consider using a different mocking framework that supports non-overridable members, such as JustMock or Typemock. These frameworks can handle non-overridable members but may come with additional complexity or licensing costs.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.