PHPUnit在运行第一个测试之前设置,并在运行最后一个测试之后拆除

lstz6jyr  于 2023-01-29  发布在  PHP
关注(0)|答案(3)|浏览(167)

我正在尝试使用PHPUnit为php应用程序实现一个类似Django的测试工具。所谓类似Django,我的意思是在运行第一个测试之前从主数据库创建一个单独的测试数据库,在运行最后一个测试之后删除它。即使一次运行许多测试用例,测试数据库也只需要创建一次。
为此,我采取了以下方法-
我定义了一个自定义测试套件类,这样我就可以在其setup和teardown方法中编写创建和删除数据库的代码,然后使用该类运行测试,如下所示

$ phpunit MyTestSuite

MyTestSuite定义了一个名为suite的静态方法,其中我只使用glob并向testsuite添加测试,如下所示

public static function suite() {
    $suite = new MyTestSuite();

    foreach (glob('./tests/*Test.php') as $tc) {
        require_once $tc;
        $suite->addTestSuite(basename($tc, '.php'));
    }

    return $suite;
}

所有测试用例类都扩展自PHPUnit_Framework_TestCase的子类,该类的setup和teardown方法负责从json fixture文件加载和清除初始数据。
现在,随着测试数量的增加,我需要一次只运行一个选定的测试,但是由于我已经使用测试套件加载测试,所以不能使用--filter选项,这让我觉得这种方法可能不正确。
所以我的问题是,在运行第一个测试之前和运行最后一个测试之后,不管PHPUnit如何找到它们,正确的方法是什么?
PS:我没有使用PHPUnit_Extensions_Database_TestCase,而是使用我自己的创建、填充和删除数据库的实现。

tct7dpnv

tct7dpnv1#

我最近遇到了需要解决同样问题的问题,我尝试使用定制类的__destruct方法运行Edorian's answer,但它似乎在每个测试结束时运行,而不是在 * 所有 * 测试结束时运行。
我没有在bootstrap.php文件中使用一个特殊的类,而是使用PHP的register_shutdown_function函数来处理所有测试结束后的数据库清理,而且似乎工作得很好。
下面是我的bootstrap.php文件中的一个示例

register_shutdown_function(function(){
   some_db_cleanup_methods();
});
ldxq2e6h

ldxq2e6h2#

我的两个自发的想法没有使用"Test Suites"。一个使用的在底部。

测试监听器

使用**PHPUnits test listeners**,您可以执行

public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
       if($suite->getName() == "yourDBTests") { // set up db
  }

  public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
       if($suite->getName() == "yourDBTests") { // tear down db
  }

您可以在xml配置文件中定义testsuite中的所有DB测试,如下所示**in the docs**

<phpunit>
  <testsuites>
    <testsuite name="db">
      <dir>/tests/db/</dir>
    </testsuite>
    <testsuite name="unit">
      <dir>/tests/unit/</dir>
    </testsuite>
  </testsuites>
</phpunit>

引导

使用phpunits引导文件,您可以创建一个类来创建DB,并在进程结束时在其自己的__destruct方法中将其拆除。
将对对象的引用放在某个全局范围内可以确保对象只在所有测试结束时才被解构(正如@beanland指出的:使用register_shutdown_function()更有意义!)

使用测试套件:

http://www.phpunit.de/manual/3.2/en/organizing-test-suites.html显示:

<?php

class MySuite extends PHPUnit_Framework_TestSuite
{
    public static function suite()
    {
        return new MySuite('MyTest');
    }

    protected function setUp()
    {
        print "\nMySuite::setUp()";
    }

    protected function tearDown()
    {
        print "\nMySuite::tearDown()";
    }
}

class MyTest extends PHPUnit_Framework_TestCase
{
    public function testWorks() {
        $this->assertTrue(true);
    }
}

这在PHPUnit 3.6中很好用,在3.7中也会很好用。当前的文档中没有,因为“测试套件类”有些不赞成/不鼓励,但它们将存在相当长的一段时间。
请注意,为每个测试用例拆除并设置整个数据库对于对抗测试间的依赖性非常有用,但如果您不在内存(如sqlite内存)中运行测试,速度可能不值得。

oxf4rvwz

oxf4rvwz3#

2020年,@edorian的方式已经是deprecated

/**
 * @throws Exception
 *
 * @deprecated see https://github.com/sebastianbergmann/phpunit/issues/4039
 */
public function testSuiteLoaderClass(): string
{
    ///
}

来源

新溶液

现在我们需要通过扩展来使用TestRunner。在phpunit.xml中添加以下代码:

<extensions>
    <extension class="Tests\Extensions\Boot"/>
</extensions>
<testsuites>
  ...
</testsuites>

Tests/Extensions/Boot.php

<?php

namespace Tests\Extensions;

use PHPUnit\Runner\AfterLastTestHook;
use PHPUnit\Runner\BeforeFirstTestHook;

class Boot implements BeforeFirstTestHook, AfterLastTestHook
{
    public function executeBeforeFirstTest(): void
    {
        // phpunit --testsuite Unit
        echo sprintf("testsuite: %s\n", $this->getPhpUnitParam("testsuite"));

        // phpunit --filter CreateCompanyTest
        echo sprintf("filter: %s\n", $this->getPhpUnitParam("filter"));

        echo "TODO: Implement executeBeforeFirstTest() method.";
    }

    public function executeAfterLastTest(): void
    {
        // TODO: Implement executeAfterLastTest() method.
    }

    /**
     * @return string|null
     */
    protected function getPhpUnitParam(string $paramName): ?string
    {
        global $argv;
        $k = array_search("--$paramName", $argv);
        if (!$k) return null;
        return $argv[$k + 1];
    }
}

执行

纯PHP:

phpunit --testsuite Unit --filter CreateCompanyTest

拉腊维尔:

php artisan test --testsuite Unit --filter CreateCompanyTest

输出:

PHPUnit 9.3.10 by Sebastian Bergmann and contributors.

testsuite: Unit
filter: CreateCompanyTest
TODO: Implement executeBeforeFirstTest() method.

相关问题