如何在symfony 5 bundle中重用代码?第6部分。测试

让我们谈谈如何停止项目之间的复制粘贴并将代码转移到可重用的symfony 5插件包中。一系列总结我对包的经验的文章将在实践中引导您创建最小的包,并将演示应用程序重构为测试和包发布周期。


在上一部分中,我们创建了bundle配置在本文中,我们将分析如何测试包,编写一些测试以及在包内创建一个微型应用程序以运行它们。


系列内容

如果您没有按顺序完成本教程,请从存储库下载应用程序,然后切换到5配置分支


有关在文件中安装和启动项目的说明README.md您可以在6测试分支中找到本文代码的最终版本


将测试移植到套件


在重构之前,已经编写了2个测试:一个服务的单元测试和控制器的功能测试。


我们有一个原始应用程序,其中基础结构层(DB)没有与域逻辑分开:测试使用临时的sqlite数据库。


检查测试是否有效:


./vendor/bin/simple-phpunit

Error: Class 'App\Service\EventExporter\Exporters\GoogleCalendarExporter' not found

测试将名称空间名称App\保留在代码中,直到将其转移到包中为止。


在这两个测试中,将名称空间固定在上bravik\CalendarBundle并再次运行。
测试必须成功通过。


在包的根目录中,创建一个文件夹testsbundles/CalendarBundle/tests),然后将tests/Service单元测试文件夹移动到该文件夹​​中我们稍后Controller再将功能测试转移到该文件夹中


从捆绑包运行单元测试


要运行测试,我们需要在捆绑软件中安装PHPUnit:


cd bundles/CalendarBundle
composer require symfony/phpunit-bridge --dev

这会将PHP Unit作为dev依赖项添加到该composer.json包中,并创建一个file composer.lock我们不需要捆绑销售:创建.gitignore文件并将其添加到其中。


开箱即用的PHP单元将无法使用。您需要配置它:指定测试所在的位置并连接作曲家自动加载器。


- phpunit.xml.dist.


, Symfony-, 1 bootstrap:


<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="bin/.phpunit/phpunit.xsd"
         backupGlobals="false"
         colors="true"
         bootstrap="./vendor/autoload.php"
>

bootstrap composer, PHPUnit .


:


./vendor/bin/simple-phpunit

!


: - .


… ?
.



, 2 .
, — , — -.
.


, ,
-.


- Symfony — Kernel symfony/http-kernel.
, , .


. , , Symfony DI-, . symfony/framework-bundle, http-kernel.


composer require symfony/framework-bundle 

tests/App TestingKernel .


Symfony\Component\HttpKernel\Kernel , :


<?php
namespace bravik\CalendarBundle\Tests\App;

use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;

class TestingKernel extends Kernel
{
    public function __construct()
    {
        parent::__construct('test', false);
    }

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

    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        // TODO: Implement registerContainerConfiguration() method.
    }
}

composer bravik\CalendarBundle\Tests\App.


: 'test', . , .


registerBundles() . :


public function registerBundles()
{
    return [
      new CalendarBundle() 
    ];
}

registerContainerConfiguration() DI-.
.


symfony/router. , .


. src/Kernel -:


class Kernel extends BaseKernel
{
    use MicroKernelTrait;

    //...

    protected function configureRoutes(RouteCollectionBuilder $routes): void
    {
        //...
        $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob');
    }
}

, Symfony- «» MicroKernelTrait.


registerContainerConfiguration(),
-:


  • configureContainer()
  • configureRoutes(), .

:


  • TestingKernel registerContainerConfiguration(),
  • use MicroKernelTrait;
  • .

configureRoutes() config/routes.yaml :


protected function configureRoutes(RouteCollectionBuilder $routes)
{
    $routes->import(__DIR__.'/../../config/routes.yaml');
}

yaml, :


composer require symfony/yaml

.


?



tests/Controller/EventControllerTest.


HTTP . HTTP-. , .


Symfony Request, . index.php:


$request = Request::createFromGlobals();
$response = $kernel->handle($request);

, .


, Symfony HttpKernelBrowser :


composer require symfony/browser-kit --dev

:


public static function createClient()
{
    $kernel = new TestingKernel();
    return new HttpKernelBrowser($kernel);
}

public function testSomeAction()
{
    $client = static::createClient();
    $response = $client->request("/some/action");
    // Assertion on response
    // ...
}

HttpKernelBrowser. $client->request() .


, , WebTestCase, Symfony. createClient(), , createKernel(), .


, , — . KERNEL_CLASS phpunit.xml.dist:


<php>
    <server name="APP_ENV" value="test" force="true" />
    <server name="KERNEL_CLASS" value="bravik\CalendarBundle\Tests\App\TestingKernel"
            force="true" />
    <!-- ... -->
</php>

:


./vendor/bin/simple-phpunit tests/Controller/EventControllerTest.php

...


LogicException: Container extension "framework" is not registered

MicroKernelTrait. DI- «-», framework.


FrameworkBundle. :


    public function registerBundles()
    {
        return [
            new FrameworkBundle(),
            new CalendarBundle()
        ];
    }

:


InvalidArgumentException: Cannot determine controller argument for "bravik\CalendarBundle\Controller\EditorController::new()": the $entityManager argument is type-hinted with the non-existent class or interface: "Doctrine\ORM\EntityManagerInterface".

- ? EditorController?


new CalendarBundle() TestingKernel, services.yaml, .


autowiring Symfony . typehints , Symfony typehints .


, , TestingKernel.


:


composer require doctrine/orm doctrine/doctrine-bundle symfony/twig-bundle
composer require doctrine/doctrine-fixtures-bundle liip/test-fixtures-bundle --dev

TestingKernel:


public function registerBundles()
{
    return [
        new DoctrineBundle(),
        new DoctrineFixturesBundle(),
        new LiipTestFixturesBundle(),
        new TwigBundle(),
        //..
    ];
}

: tests/App/config/config.yaml:


#    
# @see https://symfony.com/doc/current/reference/configuration/framework.html#test
framework:
  test:   true

doctrine:
  #  SQLITE     var/test.db
  dbal:
    driver: pdo_sqlite
    path: "%kernel.cache_dir%/test.db"

  #  ORM- 
  orm:
    auto_generate_proxy_classes: true
    naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
    auto_mapping: true

calendar:
  enable_soft_delete: true

services:
  #  Twig,  mock-   webpack encore,
  #    
  bravik\CalendarBundle\Tests\App\TwigWebpackSuppressor:
    tags: ['twig.extension']

  #       
  bravik\CalendarBundle\Tests\Fixtures\:
    resource: '../../Fixtures'
    tags: ['doctrine.fixture.orm']

, packages, . Framework, Doctrine, .


TestingKernel:


protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader)
{
    $loader->load(__DIR__.'/config/config.yaml', 'yaml');
}

(!) , , var Symfony . .gitignore.

, dev . - , — !

, - !


, , .



, Symfony - .


您可以在6测试分支中找到本文代码的最终版本


接下来的文章中,我们将讨论如何释放新的软件包版本,而不会疼痛和痛苦,如何组织初始安装和捆绑的更新的过程。


该系列的其他文章:


1.部分最小包
2的一部分,我们拿出包中的代码和模板
第3部分集成与主机捆绑的:模板,样式,JS
第4部分接口扩展包
第5部分参数及配置
部分6.测试,该包内microapplication
第7发布周期,安装和更新


All Articles