首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何加快PHPUnit + DBUnit测试套件的执行速度?

如何加快PHPUnit + DBUnit测试套件的执行速度?
EN

Stack Overflow用户
提问于 2012-04-30 23:14:54
回答 2查看 3.7K关注 0票数 11

我遇到了PHPUnit/DBUnit的一些真正的速度问题。任何扩展PHPUnit_Extensions_Database_TestCase的东西都需要很长时间才能运行。使用189个测试,该套件大约需要8-9分钟。我希望它最多只需要30秒;-)

将数据库恢复到其初始状态似乎是一个耗时的过程,因此我们已经使数据集尽可能小,并限制了每个测试用例所需的表数。我正在使用固定设备,并尽可能多地与他人分享。

是否有任何设置或修改可以用来加快执行速度?看看MySQL服务器在整个测试过程中所做的事情,似乎发生了大量的截断/插入,但将测试数据集打包到临时表中,然后为每个测试简单地选择它们,肯定会更快。

我使用的驱动程序是带有XML测试数据集的PDO/MySQL。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-05-02 17:48:40

在谷歌搜索后,我已经设法将所需的时间从10分钟减少到1分钟。事实证明,更改my.ini/my.cnf中的一些InnoDB配置设置会有所帮助。

设置innodb_flush_log_at_trx_commit = 2似乎可以完成这项工作。更改后,重新启动MySQL服务器。

有关dev.mysql.com: innodb_flush_log_at_trx_commit的更多信息

该设置控制日志的刷新符合ACID的程度。默认值为1,表示完全符合ACID,这意味着

在每次事务提交时将日志缓冲区写出到日志文件,并对日志文件执行刷新到磁盘操作。

值为2时,将发生以下情况:

每次提交时,日志缓冲区都会写出到文件中,但不会对其执行刷新到磁盘操作。

这里的关键区别在于,因为日志不是在每次提交时都写出来的,所以操作系统崩溃或断电可能会将其清除。对于生产环境,应坚持值1。对于具有测试数据库的本地开发,值2应该是安全的。

如果您正在处理将被传输到实时数据库的数据,我建议继续使用值1。

票数 21
EN

Stack Overflow用户

发布于 2013-07-12 04:13:53

在DbUnit中创建装置的速度非常慢。使用core2duo e8400 4 4gb 1333,每次需要1.5秒。您可以使用xdebug找到瓶颈并修复它(如果可以),或者您可以执行以下操作之一:

1.)

您只能运行当前使用自定义引导程序xml开发的测试文件:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://phpunit.de/phpunit.xsd"
         backupGlobals="false"
         verbose="true"
         bootstrap="test/bootstrap.php">
    <testsuites>
        <testsuite>
            <directory>test/integration</directory>
            <exclude>test/integration/database/RoleDataTest.php</exclude>
        </testsuite>
    </testsuites>
    <php>
        <env name="APPLICATION_MODE" value="test"/>
    </php>
</phpunit>

排除部分在这里很重要。你也可以使用测试组。

2.)

代码语言:javascript
复制
namespace test\integration;


abstract class AbstractTestCase extends \PHPUnit_Extensions_Database_TestCase
{
    static protected $pdo;
    static protected $connection;

    /**
     * @return \PHPUnit_Extensions_Database_DB_IDatabaseConnection
     */
    public function getConnection()
    {
        if (!isset(static::$pdo)) {
            static::$pdo = new \PDO('pgsql:host=localhost;port=5432;dbname=dobra_test', 'postgres', 'inflames', array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
            static::$connection = $this->createDefaultDBConnection(static::$pdo);
        }
        return static::$connection;
    }

    /**
     * @return \PHPUnit_Extensions_Database_Operation_DatabaseOperation
     */

    static protected $fixtureSet = false;

    protected function getSetUpOperation()
    {
        $c = get_class($this;
        if (!$c::$fixtureSet) {
            $c::$fixtureSet = true;
            return \PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(true);
        }
        return \PHPUnit_Extensions_Database_Operation_Factory::NONE();
    }

    static protected $dataSet;

    /**
     * @return \PHPUnit_Extensions_Database_DataSet_IDataSet
     */
    public function getDataSet()
    {
        $c = get_class($this;
        if (!isset($c::$dataSet)) {
            $c::$dataSet = $this->createDataSet();
        }
        return $c::$dataSet;
    }

    /**
     * @return \PHPUnit_Extensions_Database_DataSet_IDataSet
     */
    abstract protected function createDataSet();

    protected function dataSetToRows($tableName, array $ids)
    {
        $transformer = new DataSetRowsTransformer($this->getDataSet());
        $transformer->findRowsByIds($tableName, $ids);
        $transformer->cutColumnPrefix();
        return $transformer->getRows();
    }

}

您可以覆盖TestCase。在本例中,每个测试用例将只使用一个pdo连接(您可以通过依赖注入将其注入到您的代码中),通过覆盖设置操作,您可以为每个测试用例或每个测试只设置一次fixture (取决于self::$cls = get_class($this); $cls::)。(PHPUnit的设计很糟糕,它在每次测试调用时都会创建新的实例,因此您必须修改类名来存储每个实例或每个类的变量。)在这种情况下,您必须使用@depend注释编写相互依赖的测试。例如,您可以删除在上一个测试中创建的同一行。

通过这个测试代码1.5 secs代替6 x 1.5 = 9 secs

代码语言:javascript
复制
namespace test\integration\database;

use Authorization\PermissionData;
use test\integration\AbstractTestCase;
use test\integration\ArrayDataSet;

class PermissionDataTest extends AbstractTestCase
{
    static protected $fixtureSet = false;
    static protected $dataSet;

    /** @var PermissionData */
    protected $permissionData;

    /**
     * @return \PHPUnit_Extensions_Database_DataSet_IDataSet
     */
    public function createDataSet()
    {
        return new ArrayDataSet(array(
            'permission' => array(
                array('permission_id' => '1', 'permission_method' => 'GET', 'permission_resource' => '^/$'),
                array('permission_id' => '2', 'permission_method' => 'POST', 'permission_resource' => '^/$'),
                array('permission_id' => '3', 'permission_method' => 'DELETE', 'permission_resource' => '^/$')
            ),
            'user' => array(
                array('user_id' => '1', 'user_name' => 'Jánszky László', 'user_email' => 'a@b.d', 'user_salt' => '12435')
            ),
            'user_permission' => array(
                array('user_permission_id' => '1', 'user_id' => '1', 'permission_id' => '1'),
                array('user_permission_id' => '2', 'user_id' => '1', 'permission_id' => '2')
            ),
            'role' => array(
                array('role_id' => '1', 'role_name' => 'admin')
            ),
            'role_permission' => array(
                array('role_permission_id' => '1', 'role_id' => '1', 'permission_id' => '1')
            ),
            'permission_cache' => array(
                array('permission_cache_id' => '1', 'user_id' => '1', 'permission_id' => '1'),
                array('permission_cache_id' => '2', 'user_id' => '1', 'permission_id' => '2'),
            )
        ));
    }

    public function testReadAllShouldReturnEveryRow()
    {
        $this->assertEquals($this->permissionData->readAll(), $this->dataSetToRows('permission', array(3, 2, 1)));
    }

    /** @depends testReadAllShouldReturnEveryRow */

    public function testReadAllByRoleIdShouldReturnEveryRowRelatedToRoleId()
    {
        $this->assertEquals($this->permissionData->readAllByRoleId(1), $this->dataSetToRows('permission', array(1)));
    }

    /** @depends testReadAllByRoleIdShouldReturnEveryRowRelatedToRoleId */

    public function testReadAllByUserIdShouldReturnEveryRowRelatedToUserId()
    {
        $this->assertEquals($this->permissionData->readAllByUserId(1), $this->dataSetToRows('permission', array(2, 1)));
    }

    /** @depends testReadAllByUserIdShouldReturnEveryRowRelatedToUserId */

    public function testCreateShouldAddNewRow()
    {
        $method = 'PUT';
        $resource = '^/$';
        $createdRow = $this->permissionData->create($method, $resource);
        $this->assertTrue($createdRow['id'] > 0);
        $this->assertEquals($this->getDataSet()->getTable('permission')->getRowCount() + 1, $this->getConnection()->getRowCount('permission'));
        return $createdRow;
    }

    /** @depends testCreateShouldAddNewRow */

    public function testDeleteShouldRemoveRow(array $createdRow)
    {
        $this->permissionData->delete($createdRow['id']);
        $this->assertEquals($this->getDataSet()->getTable('permission')->getRowCount(), $this->getConnection()->getRowCount('permission'));
    }

    /** @depends testDeleteShouldRemoveRow */

    public function testDeleteShouldRemoveRowAndRelations()
    {
        $this->permissionData->delete(1);
        $this->assertEquals($this->getDataSet()->getTable('permission')->getRowCount() - 1, $this->getConnection()->getRowCount('permission'));
        $this->assertEquals($this->getDataSet()->getTable('user_permission')->getRowCount() - 1, $this->getConnection()->getRowCount('user_permission'));
        $this->assertEquals($this->getDataSet()->getTable('role_permission')->getRowCount() - 1, $this->getConnection()->getRowCount('role_permission'));
        $this->assertEquals($this->getDataSet()->getTable('permission_cache')->getRowCount() - 1, $this->getConnection()->getRowCount('permission_cache'));
    }

    public function setUp()
    {
        parent::setUp();
        $this->permissionData = new PermissionData($this->getConnection()->getConnection());
    }
}

3.)

另一种解决方案是每个项目只创建一次fixture,之后在事务中使用每个测试,并在每次测试后回滚。(如果您有需要提交以检查约束的pgsql延迟代码,则这不起作用。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10386037

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档