2011-09-13 66 views
8

我的網站將有一個高級搜索。 Pleople可以去那裏搜索一個實體(例如汽車)。我創建了一些基於搜索參數檢查結果數量的測試。我想我應該寫什麼測試,然後編寫它,然後將數據添加到測試數據庫。但問題來了。當我向數據庫中插入新的值時,舊的測試會中斷。這是因爲我正在檢查記錄數...TDD:如何測試搜索?

<?php defined('SYSPATH') or die('No direct access allowed!'); 

class Search_Test extends PHPUnit_Extensions_Database_TestCase 
{ 
    /** 
    * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection 
    */ 
    public function getConnection() 
    { 
     $pdo = new PDO('mysql:dbname=db_test;host=127.0.0.1', 'root', null); 
     return $this->createDefaultDBConnection($pdo, 'db_test'); 
    } 

    /** 
    * @return PHPUnit_Extensions_Database_DataSet_IDataSet 
    */ 
    public function getDataSet() 
    { 
     $fixture = realpath(dirname(__FILE__).'/../data/fixture.xml'); 
     return $this->createXMLDataSet($fixture); 
    } 

    public function numberOfResultsDataProvider() 
    { 
     return array(
      array(1, null, null, 1), 
      array(2, null, null, 3), 
      array(3, null, null, 0), 
      array('abc', null, null, 5), 
      array(null, 1996, 2003, 3), 
      array(null, 1996, 1999, 2), 
      array(null, 2002, 2003, 1), 
      array(null, 1500, 1800, 0), 
      array(null, 2003, 2003, 1), 
      array(null, null, 2005, 4), 
      array(null, 1996, null, 4), 
      array(null, null, null, 4), 
      array(null, 2003, 1996, 0), 
      array(null, 'abc', 2003, 4), 
      array(null, '1996', '1999', 2), 
      array(2, 2003, 2005, 2), 
      array(null, null, null, 4), 
     ); 
    } 

    /** 
    * @dataProvider numberOfResultsDataProvider 
    */ 
    public function testNumberOfResults($brandId, $startYear, 
     $endYear, $numberOfResults 
    ) { 
     $search = ORM::factory('search'); 
     $search->setBrand($brandId) 
      ->setYearRange($startYear, $endYear); 
     $results = $search->results(); 
     $this->assertEquals($results->count(), $numberOfResults); 
    } 
} 
?> 

這是正常的嗎?當我創建新的測試時,我的舊測試是否應該中斷?

我的測試應該與數據綁定嗎?

我的搜索參數太多,它們將以相同的形式使用(視圖)。我應該創建測試搜索每個參數還是應該一起測試它們?我應該把它分成更多的測試課嗎?

謝謝。

+1

好問題,但也許它會更適合http://programmers.stackexchange.com。 – Maxpm

回答

6

當進行涉及數據庫的單元測試時,測試應提供將要測試的實際數據庫。它可能只是一個簡單的數據庫,它只包含與測試相關的值,比如一行匹配,一行不匹配。根據活動數據庫的特定時間點存在的快照構建一堆測試也是合理的。

實現此目的的一個特別方便的方法是給我們一個專門用於測試的Sqlite3數據庫,並設置您的應用程序將其用於測試。

0

測試應當您創建新的測試,你的測試應該是依賴於數據的不休息。需要數據庫中的特定數據的測試應將該數據放入數據庫中。如果它要求數據庫中沒有其他數據,則應該清除其他所有數據。

這當然會讓你的測試變慢 - 所以模擬出數據訪問層。

+0

這是一個高級搜索,用戶可以設置許多不同的參數。我想不可能測試每一條路徑,但可能只需要很少的測試,我不得不設置很多數據固件......這是正常的嗎?難道我做錯了什麼?謝謝。 – thom

1

如果可能的話,應該切斷代碼如何獲取數據和數據庫本身之間的關係。你的單元測試不應該依賴於數據庫,並且你偶然發現了以下幾個原因:你必須在測試中維護你的數據,創建導致其他人破壞的新測試,等等。如果你能以某種方式僞造數據訪問點並嚴格在內存中返回數據,那將是理想的情況。我不知道在PHP中會有多容易,但是圍繞您的數據訪問代碼構建一個接口並使用該接口的虛擬/模擬實現可以幫助實現這一目標。

0

我會讓每個測試方法創建自己的數據,然後保持,斷言並銷燬自己的樣本數據。

我通常會有一個共享addData()方法,然後是一個數據庫清理方法。希望你能夠以某種方式使你添加的數據可識別,以便你的清理方法可以是通用的。在你的例子中,也許你可以讓你的所有品牌標識以「test-」開頭,然後你的查詢將搜索出並刪除品牌標識'test-%'的所有記錄。

1

簡而言之:
現場數據庫

在這樣做的沒有辦法,你需要測試一個單獨的數據庫。這實際上可能是數據庫的模擬。

然後,測試之前,需要準備數據庫是在你希望它是(從夾具或導入SQL文件例如負載數據)固定狀態

然後,最好的選擇是開始數據庫事務當您打算對原始數據庫狀態進行任何修改時。

交易一旦開始,您可以在數據庫上工作。

完成測試後,您只需回滾該事務,並且數據庫處於清理狀態。

Sqlite(已經提到)在大多數情況下都可以,但它可能與實時數據庫不同。無論如何,有不同的數據庫適配器將是非常有益的。