簡體   English   中英

單元測試:測試的數據庫設置

[英]Unit-Testing: Database set-up for tests

我正在為使用數據庫的應用程序編寫單元測試,我希望能夠針對某些示例/測試數據運行該應用程序 - 但我不確定設置初始測試數據的最佳方法用於測試。

我正在尋找的是一種針對當前在調試時使用的相同數據庫(或示意性相同)運行被測代碼的方法 - 在每次測試之前,我想確保將數據庫重置為在插入測試數據之前有一個干凈的石板。

我意識到使用 IRepository 模式可以消除針對實際數據庫進行測試的復雜性,但我不確定這在我的情況下是否可行。

任何可以為我指明正確方向的建議或文章?

謝謝!

- 編輯 -

謝謝大家,這些都是很好的建議! 我可能會走模擬我的數據訪問層的路線,結合一些簡單的設置類來生成我每次測試所需的數據。

這是我嘗試使用的一般方法。 我設想在大約三個或四個級別進行測試::單元測試,交互測試,集成測試,驗收測試。

在單元測試級別,它只是代碼。 任何數據庫交互都是模擬的,可以手動或使用其中一個流行的框架,因此加載數據不是問題。 它們運行速度很快,並確保對象按預期工作。 這允許非常快速的寫測試/寫代碼/運行測試周期。 模擬對象提供每個測試所需的數據。

交互測試測試非平凡類交互的交互。 同樣,不需要數據庫,它被嘲笑了。

現在處於集成級別,我正在測試組件的集成,這就是真正的數據庫,隊列,服務,yada yada被拋入的地方。如果可以,我會使用一個流行的內存數據庫,所以初始化不是問題。 它始終是空的,我使用實用程序類來擦除數據庫並在每次測試之前加載我想要的數據,這樣測試之間就沒有耦合。

我使用內存數據庫遇到的問題是它們通常不支持我需要的所有功能。 例如,我可能需要外連接,內存數據庫不支持。 在這種情況下,我通常會在本地傳統數據庫(如MySQL)上進行測試,再次在每次測試之前擦除它。 由於應用程序在單獨的環境中部署到生產環境,因此測試周期不會觸及該數據。

我發現處理此問題的最佳方法是使用具有已知數據的靜態測試數據庫,並使用事務來確保您的測試不會更改任何內容。

在您的測試設置中,您將啟動一個事務,並且在您的測試清理中,您將回滾事務。 這使您可以修改測試中的數據,但也可以確保在測試完成時所有內容都恢復到其原始狀態。

模擬是對代碼進行單元測試的最佳方式。

就集成測試而言,我在使用像SQLite這樣的內存數據庫時遇到了一些問題,主要是因為行為和/或語法的差異很小。

我一直在使用MySql的本地實例進行多個項目的集成測試。 返回的問題是服務器設置和測試數據的創建。 我創建了一個名為Mysql.Server的小型Nuget包(請參閱https://github.com/stumpdk/MySql.Server上的更多內容),它只是在每次運行測試時設置MySql的本地實例。

運行此實例后,您可以輕松地為測試設置表結構和樣本數據,而無需關注生產環境或本地服務器設置。

我知道你在使用C#,但在Java World中有Spring框架。 它允許您在事務中運行數據庫微型操作,在此事務之后,您可以回滾它。 這意味着您可以在測試完成后不觸及狀態而對真實數據庫進行操作。 也許這可能是C#進一步調查的暗示。

此代碼清除MS SQL Server中所有用戶表中的所有數據:

private DateTime _timeout;

public void ClearDatabase(SqlConnection connection)
{
    _timeout = DateTime.Now + TimeSpan.FromSeconds(30);
    do
    {
        SqlCommand command = connection.CreateCommand();
        command.CommandText = "exec sp_MSforeachtable 'DELETE FROM ?'";
        try
        {
            command.ExecuteNonQuery();
            return;
        }
        catch (SqlException)
        {
        }
    } while (!TimeOut());

    if (TimeOut())
        Assert.Fail("Fail to clear DB");
}

private bool TimeOut()
{
    return DateTime.Now > _timeout;
}

如果您正在考慮真正的數據庫使用,那么很可能我們在這里談論的是集成測試。 即測試,將應用程序行為檢查為不同組件的組合,這與單元測試相反,單元測試應該單獨測試組件。

定義了測試范圍后,我不建議像其他作者建議的那樣使用內存數據庫或模擬庫之類的東西。 問題是通常內存數據庫的行為略有不同或減少了一組功能,並且根本沒有模擬數據庫,因此您將測試一般意義上的其他應用程序,而不是您將要測試的應用程序交付給您的客戶。

我寧願建議通過僅覆蓋邏輯的關鍵部分而將其余部分用於單元測試來最小化集成測試的數量,同時使用設置盡可能接近生產數據庫的真實數據庫。 如果有很多集成,測試運行可能會太慢並且非常痛苦。

您也可以使用一些技巧來優化測試執行的速度:

  • 針對它們引入的數據突變將測試拆分為 Read 和 Write,並並行運行前者,無需任何清理。 (例如,如果被測系統是 Web 應用程序並且測試更像是端到端,則 HTTP GET 請求可以安全地並行運行);
  • 對所有數據使用唯一的插入/刪除腳本並盡可能優化。 您可能會發現我目前正在開發的Reseed庫很有幫助。 它能夠為您生成插入和刪除腳本。 所以基本上你所要求的。 或者查看可用於數據庫清理的Respawn
  • 使用數據庫快照進行還原,這可能比完整的插入/刪除周期更快;
  • 將每個測試包裝在交易中,然后再將其還原(這個也不是 100% 誠實的,而且有些脆弱);
  • 通過使用數據庫池而不是唯一的數據庫來並行化您的測試。 Docker 和TestContainers可能適合這里;

我不認為有一個簡單的方法來完成這個。 您只需創建那些預測試sql安裝腳本和測試后的Tear-down腳本。 然后,您需要為每次運行觸發這些腳本。 很多人建議使用SQLLite進行單元測試設置。

我發現最好將我的測試轉到不同的數據庫,這樣我就可以將其擦干凈並輸入我想要的測試數據。

您可能希望將數據庫設置為可在程序中設置的內容,然后您的測試可以告訴類更改數據庫。

暫無
暫無

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

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