4

我已经尽职尽责,但我认为到目前为止没有任何问题涉及这个问题。

我有一种情况,我的 PHP 代码根据配置属性生成类定义。

类定义基本上是数据持有者,可以有:

  • 公共财产
  • 或具有提供 getter/setter 的公共接口的受保护属性。

在某些配置情况下,生成的类名将相同,但它们的文件名将不同。在真实环境中,用户只需根据他们需要的配置生成一组类定义,并在他们的应用程序中使用这些类。那里没有问题,即使用户生成了多组类定义。PHP 会很高兴地继续前进,只要在应用程序中引用一组定义。

我有两个 PHPUnit 测试用例,我使用具有由任一配置生成的不同定义的类进行基本相同的测试。我在所有代码中都使用“require_once”,并在单元测试中使用相同的方法,“require_once”仅包含该测试所需的类文件。

PHPUnit 配置为运行它在我的测试目录下找到的所有测试,并且正常运行。当我为不同的类生成添加测试时,PHPUnit 停止工作并出现 PHP 致命错误:无法重新声明类。

现在,PHPUnit 的默认行为似乎是一次性加载所有测试需要运行的所有类。即使在运行任何测试之前,这也会导致致命的 PHP 错误,因为 PHPUnit 为生成的类选择了第二个定义(它们具有相同的类名但不同的文件名),即使我在每个中只“require_once”了正确的类定义测试文件。

我仍然可以运行测试,但一次只能使用一个测试文件,因此目前我必须手动或通过批处理文件运行所有测试。不可能获得所有测试的完整代码覆盖率报告。

我想要的行为是 PHPUnit 只加载每个测试文件“require_once”ed 的类,而不是它认为是从 phpunit.xml 配置运行的所有测试文件。或者更好的方法是 PHPUnit 只为所有指定的测试加载自己的类,让 PHP 自己为每个测试执行用户“require_once”。

有没有办法解决这个问题?我查看了 PHPUnit 配置设置,但似乎没有一个适合特定问题。我对幕后的 PHPUnit 并不十分熟悉,因此构建另一个测试套件加载器会很困难。

最好做一个简单的例子。这里有几个 PHPUnit 测试文件 foo1Test.php 和 foo2test.php。它们之间的唯一区别是它们需要一个不同的类文件,该类文件具有 Foo 类的定义。所有这些类都是空的并不重要,它们都是完全合法的,并且很好地说明了问题。我只是将所有这些文件放在一个“testfoo”目录中并在它们上运行 PHPunit。你也可以这样做,你会得到相同的结果。

foo1Test.php

<?php

require_once dirname ( __FILE__ ).'/Foo1.php';

class Foo1TestCase extends PHPUnit_Framework_TestCase
{
}

?>

foo2Test.php

<?php

require_once dirname ( __FILE__ ).'/Foo2.php';

class Foo2TestCase extends PHPUnit_Framework_TestCase
{
}

?>

Foo1.php

<?php

class Foo
{
}

?>

Foo2.php

<?php

class Foo
{
}

?>

foo1Test.php 和 foo2Test.php 这两个测试文件是完全有效的文件,并通过以下 PHPunit 命令行运行

phpunit foo1Test.php
phpunit foo2Test.php

如您所料,PHPUnit 未能抱怨没有测试,这很好。

我还有一个标准的 phpunit.xml 配置文件,它将在当前目录下运行所有​​测试。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupStaticAttributes="false"
         cacheTokens="false"
         colors="false"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         forceCoversAnnotation="false"
         mapTestClassNameToCoveredClassName="false"
         printerClass="PHPUnit_TextUI_ResultPrinter"
         processIsolation="false"
         stopOnError="false"
         stopOnFailure="false"
         stopOnIncomplete="false"
         stopOnSkipped="false"
         testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader"
         strict="false"
         verbose="true">
    <testsuite name="fooTests">
        <directory>.</directory>
    </testsuite>
</phpunit>

我使用此配置运行 PHPUnit,如下所示

phpunit

输出是:

PHP Fatal error:  Cannot redeclare class Foo in /var/www/testfoo/Foo2.php on line 4
PHP Stack trace:
PHP   1. {main}() /usr/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP   3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:130
PHP   4. PHPUnit_TextUI_Command->handleArguments() /usr/share/php/PHPUnit/TextUI/Command.php:139
PHP   5. PHPUnit_Util_Configuration->getTestSuiteConfiguration() /usr/share/php/PHPUnit/TextUI/Command.php:671
PHP   6. PHPUnit_Util_Configuration->getTestSuite() /usr/share/php/PHPUnit/Util/Configuration.php:768
PHP   7. PHPUnit_Framework_TestSuite->addTestFiles() /usr/share/php/PHPUnit/Util/Configuration.php:848
PHP   8. PHPUnit_Framework_TestSuite->addTestFile() /usr/share/php/PHPUnit/Framework/TestSuite.php:419
PHP   9. PHPUnit_Util_Fileloader::checkAndLoad() /usr/share/php/PHPUnit/Framework/TestSuite.php:358
PHP  10. PHPUnit_Util_Fileloader::load() /usr/share/php/PHPUnit/Util/Fileloader.php:79
PHP  11. include_once() /usr/share/php/PHPUnit/Util/Fileloader.php:95
PHP  12. require_once() /var/www/testfoo/foo2Test.php:3

这就是这个问题的意义所在。尽管测试文件在隔离时完全有效,但 PHPUnit 不会在测试套件下运行测试,因为它已尝试在运行任何测试之前加载整个测试套件所需的所有类。

在我看来,PHPUnit 在这里做错了事情,因为它选择了不应该用于特定测试的依赖项。

4

0 回答 0