【问题标题】:Understanding imports / use in PHPUnit了解 PHPUnit 中的导入/使用
【发布时间】:2019-10-28 06:26:16
【问题描述】:

在 PHPUnit 测试中,我试图让我的 symfony 应用程序的所有类都实现了某个接口。我的应用程序代码位于命名空间App,我的测试位于Tests

此测试用例代码仅列出一个类如果我实例化(或“使用”)它(顶部的use 语句无效):

namespace Tests\ReportPlaceholder;

use App\ReportPlaceholder\LimitModificationsPlaceholder;
use App\ReportPlaceholder\SimpleEvaluatePlaceholder;
use App\ReportPlaceholder\ReportPlaceholderInterface;

class MyTest extends KernelTestCase{


    public function provider(){

        new SimpleEvaluatePlaceholder(); // <-- if I comment this line, the class is *not* found
        // also a usage of SimpleEvaluatePlaceholder::class suffices

        return array_map(function($p) { return [$p]; }, 
                array_filter(get_declared_classes(), function($className){
                     return in_array(ReportPlaceholderInterface::class, class_implements($className));}
        ));
    }
}

provider 在这种情况下只返回SimpleEvaluatePlaceholder

我的 composer.json 是

"autoload": {
    "psr-4": {
        "App\\": "src/"
    }
},
"autoload-dev": {
    "psr-4": {
        "Tests\\": "tests/"
    }
},

phpunit.xml 内容如下:

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.5/phpunit.xsd"
     backupGlobals="false"
     colors="true"
     bootstrap="config/bootstrap.php"
     verbose="true"
     debug="false"
     stopOnFailure="true">

【问题讨论】:

    标签: php symfony phpunit


    【解决方案1】:

    由于您使用KernelTestCase,您可以访问容器,您可以通过标记所有实现您的接口的服务并通过以下方式将它们传递给注册表服务来轻松实现它(Symfony 3.4或更高)

    # services.yml
    services:
      _instanceof:
        YourInterface:
          tags: ['my_custom_tag']
    
      App\Registry\MyCustomTagRegistry:
        arguments: [!tagged my_custom_tag]
    

    您的注册表类:

    class MyCustomTagRegistry
    {
      /** @var Traversable */
      private $services;
    
      public function __construct(iterable $services = [])
      {
        $this->services = $services;
      }
    
      public function getServices(): array
      {
        return (array) $this->services;
      }
    }
    

    然后在您的测试中,您需要从容器中获取给定的服务:

    $services = self::$container->get(MyCustomTagRegistry::class)->getServices();
    

    您可以在此处找到有关如何使用服务标签的更多详细信息:

    【讨论】:

    • 这个解决方案是完美的,除了在构建内核和容器的位置 before setUp 调用数据提供者之外。但是我可以尝试在数据提供者中启动一个虚拟内核,只是为了获得一个公开标记服务的服务......
    • 为什么不在setUp 中启动内核?
    • 我实际上正在这样做,但是在所有测试功能之前以及每个setUp调用phpunit.de/manual/3.7/en/…之前调用数据提供者一次
    • 如果您的 Dataprovider 在 setUp 之前被调用,也许您可​​以在启动后获取 setUp 中的服务并将它们存储在实例级别 ($this-&gt;services = self::$container-&gt;get(MyCustomTagRegistry::class)-&gt;getServices();) 的数组中,而不是使用dataprovider,你可以在你的测试中简单地循环遍历这个数组。
    • 是的,我想这样的解决方法是可以的。我应该接受从数据提供者的容器中获取数据并不是一个好的测试设计。谢谢大家!到此结束
    【解决方案2】:

    我的解决方案类似于@peetya 的设想:我必须在provider 中启动一个额外的内核来获取服务列表(然后立即再次关闭它):

    public function provider()
    {
        $ret = [];
        self::bootKernel();
        foreach (static::$container->get('report_helper')->placeholders as $placeholder){
            /** @var $placeholder ReportPlaceholderInterface */
            $ret[] = [get_class($placeholder)];
        }
        static::ensureKernelShutdown();
        return $ret;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-11-06
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-31
      • 2014-09-01
      相关资源
      最近更新 更多