Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use DbContext.Database in C# unit test cases using MOQ and Xunit

Tags:

c#

.net

moq

xunit

The problem statement looks lengthy but I have tried my best to make it as simple as possible.

I have a small function inside SchedulerLPOP10ReportDataView class which uses DbContext Object as:

public async Task<IEnumerable<T>> GetReportViewData<T>(OneFpsReportsDbContext dbContext)     
{
    var defaultTimeOut = dbContext.Database.GetCommandTimeout();
                            
    dbContext.Database.SetCommandTimeout(new TimeSpan(0,20,0));
    var results = await dbContext.VW_Report.FromSqlRaw($"SELECT * from [Analytics].[VW_LPOP10_Report_Scheduling]).ToListAsync();
    dbContext.Database.SetCommandTimeout(defaultTimeOut);
    return (IEnumerable<T>)(results);      
            
}

The OneFpsReportsDbContext class syntax looks like:

    public partial class OneFpsReportsDbContext : DbContext
    {
        public OneFpsReportsDbContext()
        {
        }
    
        public OneFpsReportsDbContext(DbContextOptions<OneFpsReportsDbContext> options)
            : base(options)
        {
        }
       //code
    }

I have written test case as:

[Fact]
public void GetReportViewData_OK()
{
    // Arrange
    
    var unitUnderTest = new SchedulerLPOP10ReportDataView(It.IsAny<int>());

    var mockSet = new Mock<DbSet<DbContext>>();
    var MockOneFpsReportsDbContext1 = new Mock<OneFpsReportsDbContext>();
    TimeSpan ts3 = TimeSpan.FromMinutes(20);
    MockOneFpsReportsDbContext1.Setup(x => x.Database.SetCommandTimeout(ts3)); //[1] error

    //Act
    var res = unitUnderTest.GetReportViewData<ISchedularReportDataView>(MockOneFpsReportsDbContext1.Object, WhereClause, sqlParameters).Result;

    //Assert
}

At [1] error I get this:

Unsupported expression: ... => ....SetCommandTimeout(ts3) Extension methods (here: RelationalDatabaseFacadeExtensions.SetCommandTimeout) may not be used in setup / verification expressions.

I also tried the 'UseInMemoryDatabase' approach but I came to know we can't use 'GetCommandTimeout' with it. What Am I missing or doing incorrect in the //Arrange section of my test case? And How exactly can I make this mock / work? Thanks.

like image 887
Abhishek_Singh_Rana Avatar asked Nov 23 '25 15:11

Abhishek_Singh_Rana


1 Answers

This is, unfortunately, one of the hard-to-overcome limitations of XUnit/in-memory DB combo. You basically have two choices:

  • Spin up an actual test database locally for your unit testing purposes. In this case you'll be closer to production, but your test would kinda turn from unit into integration since you'll lack proper isolation

  • Create a wrapper class around the DbContext plus extension methods you need and mock that class instead.

The latter will look like this:

public class DbContextWrapper: OneFpsReportsDbContext
{
    public void SetCommandTimeout(TimeSpan ts)
    {
        this.Database.SetCommandTimeout(ts);
    }
}

// Then inside the usage block
public async Task<IEnumerable<T>> GetReportViewData<T>(DbContextWrapper dbContext)     
{
    var defaultTimeOut = dbContext.Database.GetCommandTimeout();
                            
    dbContext.SetCommandTimeout(new TimeSpan(0,20,0));
    var results = await dbContext.VW_Report.FromSqlRaw($"SELECT * from [Analytics].[VW_LPOP10_Report_Scheduling]").ToListAsync();
    dbContext.Database.SetCommandTimeout(defaultTimeOut);
    return (IEnumerable<T>)(results);                 
}

// And in the test:

[Fact]
public void GetReportViewData_OK()
{
    // Arrange
    
    var unitUnderTest = new SchedulerLPOP10ReportDataView(It.IsAny<int>());

    var mockSet = new Mock<DbSet<DbContext>>();
    var MockOneFpsReportsDbContext1 = new Mock<DbContextWrapper>();
    TimeSpan ts3 = TimeSpan.FromMinutes(20);
    MockOneFpsReportsDbContext1.Setup(x => x.SetCommandTimeout(ts3)); //[1] error

    //Act
    var res = unitUnderTest.GetReportViewData<ISchedularReportDataView>(MockOneFpsReportsDbContext1.Object, WhereClause, sqlParameters).Result;

    //Assert
}
like image 197
Sergey Kudriavtsev Avatar answered Nov 25 '25 04:11

Sergey Kudriavtsev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!