8

我的网站将有一个高级搜索。人们可以去那里搜索一个实体(例如汽车)。我创建了一些基于搜索参数检查结果数量的测试。我想我应该写什么测试,然后我写它,然后我将数据添加到测试数据库中。但问题来了。当我将新值插入数据库时​​,我的旧测试会中断。那是因为我正在检查记录的数量...

<?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);
    }
}
?>

正常吗?当我创建新测试时,我的旧测试是否应该中断?

我的测试应该受限于数据吗?

我的搜索有太多参数,它们将以相同的形式(视图)使用。我应该为每个参数创建测试还是应该一起测试?我应该把它分成更多的测试课吗?

谢谢。

4

5 回答 5

6

在进行涉及数据库的单元测试时,测试应提供它将测试的实际数据库。它可能只是一个简单的数据库,仅包含与测试相关的值,例如匹配的一行和不匹配的一行。针对在特定时间点存在的实时数据库的快照构建一堆测试也是合理的。

实现此目的的一种特别方便的方法是为我们提供一个专门用于测试的 Sqlite3 数据库,并将您的应用程序设置为将其用于测试。

于 2011-09-13T23:19:27.723 回答
1

简而言之:
无法在实时数据库上执行此操作

您需要一个单独的数据库进行测试。这实际上可能是数据库的模拟。

然后,在测试之前,您需要准备好数据库,使其处于您期望的固定状态(例如从夹具加载数据或导入 sql 文件)。

然后,最好的选择是在您计划对原始数据库状态进行任何修改时启动数据库事务。

一旦事务开始,您就可以在数据库上工作。

完成测试后,您只需回滚事务,并使数据库处于干净状态。

Sqlite(已经提到)在大多数情况下都可以,但它可能与实时数据库不同。无论如何,拥有不同的数据库适配器将非常有帮助。

于 2011-09-14T16:14:45.967 回答
1

如果可能的话,您应该切断代码获取数据的方式与数据库本身之间的联系。您的单元测试不应该依赖于数据库,并且您偶然发现了以下几个原因:您必须跨测试维护数据,创建新测试会导致其他测试中断,等等。如果您可以以某种方式伪造数据访问点并严格在内存中返回数据,那将是理想的情况。我不知道在 PHP 中它有多容易,但是围绕您的数据访问代码构建一个接口并使用该接口的假/模拟实现可以大大有助于实现这一目标。

于 2011-09-14T00:21:57.627 回答
0

当您创建新测试时,您的测试不应中断,并且您的测试不应依赖数据。需要数据库中特定数据的测试应将该数据放入数据库中。如果它要求数据库中没有其他数据,它应该清除所有其他数据。

当然,这会使您的测试变慢 - 所以模拟数据访问层。

于 2011-09-13T23:20:28.720 回答
0

我会让每个测试方法创建自己的数据,然后进行搜索、断言,然后销毁自己的样本数据。

我通常会有一个共享的 addData() 方法,然后是一个数据库清理方法。希望您能够以某种方式使您添加的数据可识别,以便您的清理方法可以通用。在您的示例中,也许您可​​以让所有brandId 都以“test-”开头,然后您的查询将搜索并删除brandId 像“test-%”的所有记录。

于 2011-09-14T02:54:56.880 回答