【问题标题】:TDD: How to test a search?TDD:如何测试搜索?
【发布时间】:2011-11-16 14:23:24
【问题描述】:

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

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

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

我的测试应该绑定到数据吗?

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

谢谢。

【问题讨论】:

标签: php testing tdd phpunit redgreen


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 这是一个高级搜索,用户可以设置许多不同的参数。我想不可能测试每条路径,但可能只需要很少的测试,我就必须设置很多数据夹具......这正常吗?难道我做错了什么?谢谢。
        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 2017-04-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多