【问题标题】:Dealing with path issues with PHPUnit使用 PHPUnit 处理路径问题
【发布时间】:2010-12-11 20:29:09
【问题描述】:

我刚开始使用 PHPUnit,但遇到了一些障碍。

我的代码使用 $_SERVER['DOCUMENT_ROOT'] 来计算包含的路径,当我的 apache 服务器是运行 PHP 的服务器时,它可以工作,但是当我使用“phpunit 测试”从命令行运行 phpunit 时,没有设置 DOCUMENT_ROOT,所以这些包括不起作用。

我在 PHPUnit 的配置中遗漏了什么吗?它应该以某种方式与apache集成吗?

【问题讨论】:

    标签: php unit-testing testing phpunit include


    【解决方案1】:

    最好的方法是将您的代码与$_SERVER 或任何其他全局数组的使用分离。比如做

    class MyClass
    {
        protected $_docroot;
    
        public function __construct($docroot)
        {
            $this->_docroot = $docroot;
        }
    
        public function getDocRoot() 
        {
            return $this->_docroot;
        }
    }
    

    而不是

    class MyClass
    {
        public function getDocRoot() 
        {
            return $_SERVER['DOCUMENT_ROOT'];
        }
    }
    

    这可以让你做

    // in your actual code
    $instance = new MyClass($_SERVER['DOCUMENT_ROOT']);
    $docroot = $instance->getDocRoot();
    
    // in your test
    $instance = new MyClass($variable_holding_the_correct_path);
    $docroot = $instance->getDocRoot();
    

    请注意,这只是一个简单的解耦示例。在您的情况下可能要复杂得多 - 但通常值得付出努力,尤其是在您运行单元测试时。

    【讨论】:

    • 那么问题就变成了,如何包含包含这个类的文件?
    • 嗯,好的 - 我明白了问题......我有点误解了你问题的真实背景。您不应依赖使用任何环境变量(包括$_SERVER['DOCUMENT_ROOT'])来包含文件。您是否有可能使用相对路径包含文件,例如require_once dirname(__FILE__) . '/MyClass.php'?另一方面,您可以设置某种自动加载...
    【解决方案2】:

    回复晚了,抱歉。

    不,你没有错过任何东西。 PHP CLI(用于命令行的 PHP)与作为 Apache / CGI 模块的 PHP 不同。

    您可以做的是将文件的setUp() 更改为您需要的设置$_SERVER['DOCUMENT_ROOT'](因为即使在CLI 上下文中$_SERVER 仍可用作超全局),例如:

    public function setUp() {
      $_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__) . "/../application";
    }
    

    请注意,您可能想将其放入您的tearDown():

    public function tearDown() {
      unset($_SERVER['DOCUMENT_ROOT']);
    }
    

    PHPUnit backs up your global state 如果您完全使用全局(也是超全局)数据,这可能会显着降低您的测试速度,因此最好避免在测试运行后使用任何数据。

    【讨论】:

    • 这绝对有效,但是为什么,如果您总是可以使用正确的方法通过 phpunit.xml 设置其他变量?
    • @TheGodfather 两个原因:一,这个答案是从 2010 年开始的,从那时起发生了很大变化,包括你提到的。 :) 第二,您可能希望为不同的测试或测试集设置不同的值,而不是全局设置它们,尽管这应该很少见。因此,感谢您添加对此问题的答案。我已经投了赞成票。我不能接受它,但我希望 OP 看到它并知道这些天有更好的方法。
    【解决方案3】:

    $_SERVER['DOCUMENT_ROOT']也可以在Bootstrap文件中设置,同样的Bootstrap_test.php附加到phpunit配置文件phpunit.xml,属性名bootstrap=Bootstrap_test.php

    我能够实现为 Jenkins 作业配置设置 $_SERVER['DOCUMENT_ROOT'] 的要求。 “Bootstrap_test.php”看起来像

    <phpunit
    
       backupGlobals="false"
    
       backupStaticAttributes="false"
    
       strict="true"
    
       verbose="true"
    
       bootstrap="Bootstrap_test.php">
    
       <testsuites>
    
         <testsuite name="PHPUnit Test Suite">
    
         <file>PHPUnitTest.php</file>
    
         </testsuite>
    
       </testsuites>
    
       <logging>
    
         <log type="coverage-clover" target="logs/clover.xml"/>
    
       </logging>
    
    </phpunit>
    

    并且Bootstrap.php 中的内容是使用define() 函数声明的:

    define('BASE_PATH', realpath(dirname(__FILE__)));    
    $_SERVER['DOCUMENT_ROOT'] = BASE_PATH;
    

    BASE_PATH 变量通常包含 Jenkins 作业目录的完整路径。比如说,Jenkins 的工作名称是Test_Job。 Jenkins将放置项目源代码的目录是/var/lib/jenkins/jobs/Test_Job/workspace(假设jenkins工作目录为/var/lib/jenkins)。

    如果将 Bootstrap_test.php 放在基目录下,BASE_PATH 将持有/var/lib/jenkins/jobs/Test_Job/workspace,最后设置为$_SERVER['DOCUMENT_ROOT']。

    【讨论】:

      【解决方案4】:

      只想记录 从 PHPUnit 测试中调用另一个 php 文件(如 config.php)。
      我有一个测试类:

      class xyzTest extends TestCase {
      
          public static function setUpBeforeClass() {
              require_once __DIR__ . '/../../app/config/Config.php';
          }
      
      ...
      

      在config.php 我设置了一些常量,比如文件路径。这些路径相对于$_SERVER['DOCUMENT_ROOT']。
      我想使用这些路径常量测试我的 xyz 类。
      但是,当从命令行调用 PHPUnit 时,$_SERVER 超全局为空。我尝试遵循 answer above 的好建议,并在 PHPUnits setUp 方法中设置 $_SERVER['DOCUMENT_ROOT']。这并没有解决我的问题。

      我通过在我的Config.php 中添加一个if 语句来修复它,如下所示:

      if ($_SERVER['DOCUMENT_ROOT']) {
          $DocumentRoot = realpath($_SERVER['DOCUMENT_ROOT']);
      } else {
          $DocumentRoot = realpath(dirname(__FILE__) . '/../..'); //for PHPUnit
      }
      

      希望这可以避免一些人头疼。

      【讨论】:

        【解决方案5】:

        您可以直接在phpunit.xml 中的php 部分中设置其他变量(无论如何您都会在某个时候使用),而不是将黑客注入生产代码或测试代码:

        <phpunit bootstrap="vendor/autoload.php">
        
            <php>
                <server name="DOCUMENT_ROOT" value="wwwroot" />
                <server name="SERVER_NAME" value="localhost" />
        
                <const name="PHPUNIT_TESTSUITE" value="true"/>
            </php>
        </phpunit>
        

        请参阅official documentation 了解其他可能的选项

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-02
          • 2011-03-07
          • 1970-01-01
          相关资源
          最近更新 更多