使用SQLite数据库时并行化功能测试

时间:2015-03-11 11:06:29

标签: sqlite symfony phpunit parallel-testing liipfunctionaltestbundle

我在Symfony2项目中添加了许多测试,但现在有53个测试和176个断言需要大约一分钟。我正在努力减少这段时间,因为如果我启用代码覆盖率报告则需要15分钟。

  

$ phpunit -c app / phpunit.xml.dist由Sebastian Bergmann撰写的PHPUnit 4.3.5。
  配置从app / phpunit.xml.dist读取   .................................................. ...
  时间:59.1秒,记忆:361.00Mb
  好的(53个测试,176个断言)

我已正确配置LiipFunctionalTestBundle以在test环境中使用SQLite数据库(LiipFunctionalTestBundle建议这样做):

应用程序/配置/ config_test.yml

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   pdo_sqlite
                path:     %kernel.cache_dir%/test.db

我已经使用DoctrineFixturesBundle添加了灯具。

现在我必须创建tests suitesgroups来启动PHPUnit的多个实例。但我看到了一个未来的问题:如果两个或多个phpunit实例在同一个SQLite文件中写入和读取数据,如何可以并行化测试(例如使用paratest)?

我可以Pass a variable to PhpUnit更改kernel.cache_dir值,并为每个phpunit实例创建一个cache目录。但是无法从命令行完成,所以如果我选择这个解决方案,我将不得不创建几个phpunit.xml.dist。我正在寻找更方便的解决方案。

2 个答案:

答案 0 :(得分:1)

我通过创建与测试文件一样多的缓存目录找到了一种解决方法。

我定义了8个测试套件以适应我的CPU的8个核心:

<!-- app/phpunit.xml.dist -->
<?xml version="1.0" encoding="UTF-8"?>

<phpunit
    backupGlobals = "false"
    …
>
    …
    <testsuites>
        <testsuite name="Group1">
            <file>../src/AcmeBundle/Tests/Command/CommandTest.php</file>
            <file>…</file>
        </testsuite>
        …
        <testsuite name="Group8">
            <file>../src/AcmeBundle/Tests/Controller/AdminControllerTest.php</file>
        </testsuite>
    </testsuites>
</phpunit>

我创建了一个 phpunit.sh 脚本,该脚本使用export(由David Harkness建议,以便为每个测试套件定义特定路径:

#!/bin/bash

function test() {
    testsuite=$1
    export CACHE_PATH="$testsuite"
    OUTPUT=$(phpunit -c app/phpunit.xml.dist --testsuite $testsuite)
    RETURN=$?
    if [ $RETURN -eq 0 ]
    then
        echo -e -n "\033[01;32m●  OK\t\033[00m \033[01;35m$testsuite\033[00m"
        tail=$(echo "$OUTPUT" | tail -n 3)
        echo -e "\t\"$tail\"" | tr '\n' '\t' | tr -s '\t'
        echo ""
    else
        echo -e "\033[01;31m❌  ERROR\033[00m \033[01;35m$testsuite\033[00m (\033[01;34m$RETURN\033[00m)\033[00m"
        echo "-----"
        echo "$OUTPUT"
        echo "-----"
    fi
}

for testsuite in $(seq 1 8)
do
    tester "Group$testsuite" &
done

# http://unix.stackexchange.com/questions/231602/how-to-detect-that-all-the-child-processes-launched-in-a-script-ended/231608#231608
wait

echo "Done"

如果一切正常,成功的测试套件会显示绿色标记,并且phpunit的输出将被截断以保持较小的输出。如果有错误,将显示。

然后我将此添加到 app / AppKernel.php

/**
 * @see http://symfony.com/fr/doc/2.3/cookbook/configuration/override_dir_structure.html#surcharger-le-repertoire-cache
 */
public function getCacheDir()
{
    $cachePath = getenv('CACHE_PATH');

    if (
        ($this->environment == 'test')
        &&
        (! empty($cachePath))
    ) {
        return(parent::getCacheDir().'/'.$cachePath.'/');
    }

    # else

    return parent::getCacheDir();
}

此代码将告诉Symfony在缓存文件夹中创建一个子目录,这意味着PHPUnit的多个实例不会使用相同的SQLite文件。

虽然它有效,但这个解决方案并不完美并且有一些缺点:

  • 即使我只想更改SQLite数据库的路径
  • ,它也会重新创建整个缓存
  • 它将占用空间并花费时间为每个休息文件创建一个缓存,如果你不使用RAM作为缓存我建议你避免这种情况(我的解决方案是删除 cache in app / 并创建一个符号链接:ln -s /run/shm/project/cache cache,测试速度更快,因为缓存是在RAM中完成而不是在硬盘上完成的)

答案 1 :(得分:0)

有一个bundle可以促进与symfony的并行测试运行。它也可以用于常规数据库,而不仅仅是sqlite。不幸的是,它还为每个测试文件显示一个PHPUnit结果。但它只能在处理器实际同时执行的同时启动多个并行测试,并且它似乎也解决了缓存问题。