2014-02-05 80 views
0

我想了解涉及數據庫時的單元測試。我的課很大程度上依賴於數據庫來完成他們的工作。我已經在這裏看到了很多在stackoverflow和互聯網上的很多答案,但是我對我發現的東西並不滿意。使用Symfony 2和數據庫進行單元測試

當我涉及到一個數據庫時(參見MySQL),我看到的一個常見問題是測試真的很長,一個可能的解決方案是使用SQLite。

我不能在測試中的任何地方使用它,因爲有些類使用原始查詢而不是原則querybuilder來繞過未知日期時間函數的限制。 SQLite有一組不同的日期值函數,這意味着要在測試中使用它,我應該重寫我的查詢兩次,一次用於MySQL,一次用於SQLite。

然後我決定堅持使用MySQL,但每次測試運行時都會創建和刪除模式需要很長時間。我知道SchemaTool類可以處理模式子集的創建:只需創建測試套件中真正需要的表,是否應該使用完整模式?

的代碼部分的示例(僞代碼)我試圖測試

NotificationManagerClass 
    constructor(EntityManager) 
    loadNotifications() 
    deleteNotification() 
    updateNotification() 

,你可以看到,我在類的構造函數注入實體管理器。該類是在Symfony容器中註冊的服務。在控制器中,我得到這個服務並使用它的方法。在我使用querybuilder的方法中,因爲我必須有權訪問其他一些服務,並且存儲庫不能識別容器。我怎樣才能脫離我的課程?我想不出一種辦法

回答

4

你混合了很多單詞,它們並不都具有你給他們的意義。詞的快速摘要:

  • 單元測試 - 測試僅一個類。它不測試也不實例化任何其他類(它使用模仿或存根)。它不應該使用數據庫,它應該嘲笑教條。
  • Web測試 - 這些測試測試多個類如何使用數據庫一起工作。這些通常很慢,所以你不想在這裏進行很多非常具體的測試。
  • MySQL and SQLite都只是數據庫驅動程序。 SQLite的速度和MySQL一樣慢,你使用哪一個並不重要(嗯,它的確很重要,你必須使用與你在生產中一樣的驅動程序)

你不能嘲笑一切,因爲你決定使用原始的mysql函數(不好的選擇)......總是避免在類中使用mysql查詢。使用Doctrine(有很多簡單的方法可以繞過未知的日期時間函數),或者將原始查詢放入Repository中並模擬存儲庫。

簡而言之:

  • 不要使用任何比在單元測試中被測對象等(模擬/存根一切)
  • Web測試應該使用的生產工具
  • 不要使用mysql直接在一個類中
+0

我感謝您的回覆。我用我想要測試的例子編輯我的答案,如果你能給我一個例子說明你如何測試與數據庫連接的東西,那將是很酷的 – Stefano

+1

Mock Doctrine? o_O不要爲存儲庫編寫單元測試;改爲編寫整合測試。 –

+0

@ElnurAbdurrakhimov不是教義,而是你的存儲庫。也許我把它寫在文本錯誤:) –

2

涉及數據庫的測試不是單元測試。您的存儲庫應該使用集成或功能測試進行測試(或者如果您編寫了這些測試,則可以接受)。

如果你有很多的測試,涉及的數據庫,這可能意味着你拐錯了彎的地方,無論是與:

  • 代碼設計 - 你的類連接到數據庫
  • 決定如何測試 - 寫作太多的集成測試,而不是單元測試

可能是值得探討的測試金字塔:http://martinfowler.com/bliki/TestPyramid.html

通過研究如何加速測試,您將只會繼續走錯路。解決方案是編寫更多的單元測試和更少的集成測試。單元測試是快速,獨立和孤立的,因此難以打破。集成測試更脆弱,速度更慢。看看FIRST properties of unit tests

順便說一句:SQLite是一個死衚衕。它的行爲不像mysql,因爲它不支持約束。

你的榜樣類可以近似爲:

class NotificationManager 
{ 
    public function __construct(MyNotificationRepository $repository, MyFabulousService $service) 
    {} 

    // ... other methods 
} 

這樣就可以既注入知識庫和服務的假貨,並在隔離測試NotificationManager。

單元測試查詢構建器沒有太多價值,因爲您會測試學說而不是代碼。這也很困難,因爲查詢類被聲明爲final。您可以測試查詢是否在功能上返回正確的結果。如果你正確地單元測試你的課程,將會有很少的功能測試需要。

如果您爲MyNotificationRepository創建了一個接口,您甚至可以從教義中分離出來。

+0

謝謝爲了編輯你的答案,但是我注入了EntityManager,因爲像deleteNotification這樣的一些方法不需要存儲庫,他們需要使用查詢構建器做一些工作。我現在移動代碼以獲取存儲庫中的通知,並且管理器get *方法調用存儲庫方法 – Stefano

+0

您應該將所有查詢構建器交互移動到存儲庫。 –

+0

但我必須對需要服務容器的查詢做一些工作。不應該存儲庫只提供一種獲取數據的方式,也不能設置? – Stefano