簡體   English   中英

如何使用 MOQ 和 Xunit 在 C# 單元測試用例中使用 DbContext.Database

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

問題陳述看起來很長,但我已盡力使其盡可能簡單。

我在 SchedulerLPOP10ReportDataView class 中有一個小的 function,它使用 DbContext Object 作為:

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);      
            
}

OneFpsReportsDbContext class 語法如下所示:

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

我將測試用例編寫為:

[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
}

在 [1] 錯誤我得到這個:

不支持的表達式:... =>....SetCommandTimeout(ts3) 擴展方法(此處:RelationalDatabaseFacadeExtensions.SetCommandTimeout)不得用於設置/驗證表達式。

我還嘗試了“UseInMemoryDatabase”方法,但我知道我們不能對它使用“GetCommandTimeout”。 我在測試用例的 //Arrange 部分遺漏了什么或做錯了什么? 我怎樣才能使這個模擬/工作? 謝謝。

不幸的是,這是 XUnit/內存數據庫組合難以克服的限制之一。 你基本上有兩個選擇:

  • 為您的單元測試目的在本地啟動一個實際的測試數據庫。 在這種情況下,您將更接近生產,但您的測試會有點從單元變成集成,因為您將缺乏適當的隔離

  • 在 DbContext 周圍創建一個包裝器DbContext加上您需要的擴展方法,然后模擬該 class。

后者看起來像這樣:

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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM