TDD: 如何测试搜索功能?

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

这正常吗?我创建新的测试时,是否应该打破以前的测试?

我的测试是否应该与数据绑定?

我的搜索有太多参数,它们将在同一表单(视图)中使用。我应该为每个参数创建搜索测试还是应该同时测试它们?我应该将其拆分成更多的测试类吗?

谢谢。


1
好问题,但也许更适合发布在http://programmers.stackexchange.com上。 - Maxpm
5个回答

6

在进行涉及数据库的单元测试时,测试应该提供实际将要测试的数据库。这可能只是一个简单的数据库,其中只包含与测试相关的值,例如一行匹配和一行不匹配。根据特定时间点现有的快照生成一组针对生产数据库的测试也是合理的。

实现这一目标的一个特别方便的方法是使用 Sqlite3 数据库专门用于测试,并设置应用程序在测试中使用该数据库。


1
如果可能的话,您应该切断代码获取数据和数据库本身之间的联系。您的单元测试不应依赖于数据库,您已经遇到了一些原因:您必须在测试之间维护数据,创建新测试会导致其他测试失败等等。如果您可以以某种方式伪造数据访问点并严格返回内存中的数据,那将是理想情况。我不知道在PHP中有多容易,但围绕数据访问代码构建接口并使用该接口的虚拟/模拟实现可以在帮助实现此目标方面发挥很大作用。

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

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

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

然后,最好的选择是在计划修改原始数据库状态时开始数据库事务

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

完成测试后,只需回滚事务,即可使数据库处于清洁状态。

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


0

当你创建新的测试时,你的测试不应该出现错误,并且你的测试不应该依赖于数据。需要特定数据库中的数据的测试应该将这些数据放入数据库中。如果它要求数据库中没有其他数据,则应清除所有其他数据。

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


这是一个高级搜索功能,用户可以设置许多不同的参数。我猜不可能测试每一条路径,但也许通过少量的测试,我将不得不设置大量的数据固定装置... 这正常吗?我做错了什么吗?谢谢。 - thom

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接