PHPUnit:如何创建一个为我的所有测试调用一次的函数?

sna*_*ile 59 php phpunit

我有一个PHPUnit测试用例类(包含一些测试函数).我想oneTimeSetUp()为类中的所有测试编写一个函数来调用一次(不像标准setUp()函数,在类中为每个测试调用一次).换句话说,我正在寻找一个等效于JUnit @BeforeClass注释的PHPUnit .

oneTimeTearDown()功能相同的问题.

是否有可能在PHPUnit中这样做?

bor*_*ble 91

看看setUpBeforeClass()第6 PHPUnit文档的.

对于你应该使用的一次tearDown tearDownAfterClass();.

这两种方法都应该在您的类中定义为静态方法.

  • 有没有非静态替代品? (21认同)
  • @Martijn 不幸的是现在 phpunit 中没有方法。幸运的是,您可以通过在 setUp() 中使用一些“初始化”标志或延迟加载来覆盖这个缺失的功能。它仍然在每次测试之前执行,但如果测试类已经初始化,则不执行任何操作。 (3认同)
  • 对于`setUp`,使用标记`initialized`的fencing有效,但不适用于`tearDown`,因为你不知道哪个是最后一次测试. (3认同)
  • 我即将写同样的事情......你的答案就是答案 (2认同)

Ian*_*zzi 7

我带着同样的问题来到这个页面,但是所有课程都接受了接受的答案,而对我来说并不是正确的答案.

如果您像我一样,您的第一个"集成测试"是清除数据库,并运行迁移.这使您自己进入所有测试的数据库基线.此时我不断更改迁移文件,因此设置基线确实是所有测试的一部分.

迁移需要一段时间,所以我不希望它在所有测试上运行.

然后我需要建立测试每个部分的数据库.我需要编写一个订单测试,但首先我需要创建一些产品并进行测试,然后我需要测试一个导入功能.

所以,我所做的是SUPER easy,但在互联网上没有得到很好的解释.我创建了一个简单的测试来设置数据库.然后在你的phpspec.xml文件中添加一个testsuite ....

<testsuite name="Products">
    <file>tests/in/SystemSetupTest.php</file>
    <file>tests/in/ProductTest.php</file>
    <file>tests/in/ProductImportTest.php</file>
</testsuite>
Run Code Online (Sandbox Code Playgroud)

并在SystemSetupTest.php ....

class SystemSetupTest extends ApiTester
{

    /** @test */
    function system_init()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        self::createEM(); //this has all the code to init the system...
    }
}
Run Code Online (Sandbox Code Playgroud)

然后执行它:

phpunit --testsuite产品

最后,它更容易.它将允许我正确地建立我的系统.

另外我使用laravel 5.使用时setUpBeforeClass()我最终遇到了引导问题,我相信我可以修复,但我上面使用的方法很完美.


Gus*_*ves 6

bootstrap选项可用于这些情况。

您可以从命令行调用它

phpunit --bootstrap myBootstrap.php
Run Code Online (Sandbox Code Playgroud)

或者把它放在 XML 文件中,像这样:

<phpunit bootstrap="myBootstrap.php">
...
</phpunit>
Run Code Online (Sandbox Code Playgroud)

  • 大多数情况下,这个属性包含用于加载 composer 依赖项的 `vendor/autoload.php`。由于不能有多个 bootstrap 文件,所以这个解决方案不太合适 (2认同)
  • @Chris,您可以从引导文件中要求“vendor/autoload.php”。例如 `require __DIR__.'/../vendor/autoload.php';` (2认同)

Dan*_*ell 6

setUpBeforeClass() 如果所有测试实际上都包含在一个类中,则这是执行此操作的方法。

但是,您的问题有点暗示您可能正在将测试类用作多个测试类的基类。在这种情况下,setUpBeforeClass将在每个之前运行。如果只想运行一次,则可以使用静态变量来保护它:

abstract class TestBase extends TestCase {

  protected static $initialized = FALSE;

  public function setUp() {
    if (!self::$initialized) {
      // Do something once here for _all_ test subclasses.
      self::$initialized = TRUE;
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

最后的选择可能是测试监听器

  • 这很有帮助,但请记住添加“parent::setUp();”作为“public function setUp()”的第一行。 (2认同)
  • 这就是我在你前两天所说的话,不知何故你得到了所有的赞成票。我想知道为什么。 (2认同)

cpr*_*prn 5

扩展接受的答案:

setUpBeforeClass(), tearDownAfterClass(), @beforeClass, 中没有一个@afterClass在对象上下文中运行(静态方法)。您可以通过@before使用静态属性保护任何代码来解决该限制,如下所示:

class MyTest extends PHPUnit\Framework\TestCase
{
    private static $ready = false;

    /**
     * @before
     */
    protected function firstSetUp()
    {
        if (static::$ready))
            return;

        /* your one time setUp here */

        static::$ready = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

@after但是,它不能用于,因为无法确定上次调用的时间。