簡體   English   中英

如何在測試(單元或集成)期間處理 DatabaseFacade

[英]How to deal with DatabaseFacade during testing (Unit or Integration)

尋找一些建議。

public class SomeController : Controller
{
    private readonly SomeContextClass _context;
     
    public SomeController(SomeContextClass context)
    {
        _context = context;
    }   
}

//Context Class
public SomeContextClass : DbContext
{
    public SomeContextClass(DbContextOptions<SomeContextClass> op) : base(op){

        Database.SetCommandTimeout(9000);
    }
}

//Test
[Fact]
public void SomeController_Test()
{
    //Trying In-Memory Implementation
    var options = new DbContextOptions<SomeContextClass>().UseInMemoryDatabase(databaseName: "SomeDB").Options;

    using (var context = new SomeContextClass(options))
    {
        var sc = new SomeController(context);
    }
}

由於 setcommandtimeoutcall,嘗試初始化某個上下文類時會出現此錯誤。

有沒有辦法使用 MOQ 來模擬該調用? 在內存測試中如何處理?

您可以通過 DbContextOptions 設置它,而不是在 DbContext 配置中硬編碼超時。 這樣,上下文類保持不變。

從鏈接的文檔示例中,您可以使用以下命令設置特定於提供程序的命令超時:

optionsBuilder
    .UseSqlServer(connectionString, 
        providerOptions=>providerOptions.CommandTimeout(90));

這可以在生產或集成測試中用於為真實數據庫設置命令超時,而無需修改 DbContext:

var options = new DbContextOptions<SomeContextClass>()
        .UseSqlServer(connectionString, 
            providerOptions=>providerOptions.CommandTimeout(90))
        .Options;

Timeout 值可以來自配置,允許它在不修改代碼的情況下進行更改。

但是,使用內存中提供程序的單元測試不需要該設置,因此可以簡單地將其省略。

var options = new DbContextOptions<SomeContextClass>()
                 .UseInMemoryDatabase(databaseName: "SomeDB")
                 .Options;

我今晚看了看,正如我所料,它會拋出一個 InvalidOperationException

只有在上下文使用關系數據庫提供程序時才能使用特定於關系的方法。

當您嘗試使用諸如 FromSql、ExecuteSqlCommand 等關系方法時,這些在內存提供程序中很常見。大多數情況下,它們可以使用模擬包裝器進行模擬(我正是為我的庫EntityFrameworkCore.Testing這樣做),通常是雖然有很多工作。

SetCommandTimeout 是一個擴展。 您需要深入研究擴展並在數據庫外觀上模擬一些東西才能使其工作。

但是,在我們走這條路之前,在這種情況下,模擬對您不起作用。 當你模擬一個實現時,模擬庫需要能夠創建一個實例來代理,這意味着它在構造函數中執行代碼。 SetCommandTimeout 將在您在模擬創建期間傳入的任何 DbContextOptions 上執行,並再次 barf。

關於您的選擇:

  1. 不要在構造函數中調用 set 命令超時; 將它移動到另一個方法,記得調用它等

  2. 使用支持關系操作的不同實體框架核心提供程序

不能說我喜歡第一個選項,但它可以讓你嘲笑它。 第二個更可口。 我不會用 SQLite 做很多事情,但是在 LINQPad 中快速播放會產生預期的結果:

void Main()
{
    using (var connection = new SqliteConnection("Filename=:memory:"))
    {
        connection.Open();
        var options = new DbContextOptionsBuilder<TestDbContext>().UseSqlite(connection).Options;
        var testDbContext = new TestDbContext(options);
        Console.WriteLine(testDbContext.Database.GetCommandTimeout());
    }
}

public class TestDbContext : DbContext
{
    public TestDbContext(DbContextOptions<TestDbContext> op) : base(op)
    {
        Database.SetCommandTimeout(9000);
    }
}

結果:

在此處輸入圖片說明

不是真正的解決方案,但我想在這里留下一個解決方法的指針,因為這個答案挽救了我的一天。 我只需要 DatabaseFacade 中的一件事就可以使我的代碼可進行單元測試,最后我用我可以模擬的數據庫上下文的虛擬方法包裝它:

   public virtual bool CanConnectToDatabase()
   {
       return Database.CanConnect();
   }

暫無
暫無

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

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