2011-09-13 63 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(已经提到)在大多数情况下都可以,但它可能与实时数据库不同。无论如何,有不同的数据库适配器将是非常有益的。