<p dir="auto">I think it's a bug related with the feature <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="171062392" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/19612" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/19612/hovercard" href="https://github.com/symfony/symfony/issues/19612">#19612</a></p>
<p dir="auto">I have a route group for an admin section, and I want to prefix the URL and name of each route inside the <code class="notranslate">App\Controller\Admin</code> namespace.</p>
<p dir="auto">If I go only for the route prefix it works without any problem</p>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# config/routes.yaml
admin:
  prefix: /admin
  resource: ../src/Controller/Admin
  type: annotation"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> config/routes.yaml</span>
<span class="pl-ent">admin</span>:
  <span class="pl-ent">prefix</span>: <span class="pl-s">/admin</span>
  <span class="pl-ent">resource</span>: <span class="pl-s">../src/Controller/Admin</span>
  <span class="pl-ent">type</span>: <span class="pl-s">annotation</span></pre></div>
<p dir="auto">The router debug gives me the following output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=" -------------------------- ---------- -------- ------ ----------------------------------- 
  Name                       Method     Scheme   Host   Path                               
 -------------------------- ---------- -------- ------ ----------------------------------- 
  _twig_error_test           ANY        ANY      ANY    /_error/{code}.{_format}           
  _wdt                       ANY        ANY      ANY    /_wdt/{token}                      
  _profiler_home             ANY        ANY      ANY    /_profiler/                        
  _profiler_search           ANY        ANY      ANY    /_profiler/search                  
  _profiler_search_bar       ANY        ANY      ANY    /_profiler/search_bar              
  _profiler_phpinfo          ANY        ANY      ANY    /_profiler/phpinfo                 
  _profiler_search_results   ANY        ANY      ANY    /_profiler/{token}/search/results  
  _profiler_open_file        ANY        ANY      ANY    /_profiler/open                    
  _profiler                  ANY        ANY      ANY    /_profiler/{token}                 
  _profiler_router           ANY        ANY      ANY    /_profiler/{token}/router          
  _profiler_exception        ANY        ANY      ANY    /_profiler/{token}/exception       
  _profiler_exception_css    ANY        ANY      ANY    /_profiler/{token}/exception.css   
  index                      ANY        ANY      ANY    /admin/                            
  login                      ANY        ANY      ANY    /admin/login                       
  user_index                 GET        ANY      ANY    /admin/user                        
  user_new                   GET|POST   ANY      ANY    /admin/user/new                    
  user_show                  GET        ANY      ANY    /admin/user/{id}                   
  user_edit                  GET|POST   ANY      ANY    /admin/user/{id}/edit              
  user_delete                DELETE     ANY      ANY    /admin/user/{id}                   
  admin_logout               ANY        ANY      ANY    /admin/logout                      
 -------------------------- ---------- -------- ------ ----------------------------------- "><pre class="notranslate"><code class="notranslate"> -------------------------- ---------- -------- ------ ----------------------------------- 
  Name                       Method     Scheme   Host   Path                               
 -------------------------- ---------- -------- ------ ----------------------------------- 
  _twig_error_test           ANY        ANY      ANY    /_error/{code}.{_format}           
  _wdt                       ANY        ANY      ANY    /_wdt/{token}                      
  _profiler_home             ANY        ANY      ANY    /_profiler/                        
  _profiler_search           ANY        ANY      ANY    /_profiler/search                  
  _profiler_search_bar       ANY        ANY      ANY    /_profiler/search_bar              
  _profiler_phpinfo          ANY        ANY      ANY    /_profiler/phpinfo                 
  _profiler_search_results   ANY        ANY      ANY    /_profiler/{token}/search/results  
  _profiler_open_file        ANY        ANY      ANY    /_profiler/open                    
  _profiler                  ANY        ANY      ANY    /_profiler/{token}                 
  _profiler_router           ANY        ANY      ANY    /_profiler/{token}/router          
  _profiler_exception        ANY        ANY      ANY    /_profiler/{token}/exception       
  _profiler_exception_css    ANY        ANY      ANY    /_profiler/{token}/exception.css   
  index                      ANY        ANY      ANY    /admin/                            
  login                      ANY        ANY      ANY    /admin/login                       
  user_index                 GET        ANY      ANY    /admin/user                        
  user_new                   GET|POST   ANY      ANY    /admin/user/new                    
  user_show                  GET        ANY      ANY    /admin/user/{id}                   
  user_edit                  GET|POST   ANY      ANY    /admin/user/{id}/edit              
  user_delete                DELETE     ANY      ANY    /admin/user/{id}                   
  admin_logout               ANY        ANY      ANY    /admin/logout                      
 -------------------------- ---------- -------- ------ ----------------------------------- 
</code></pre></div>
<p dir="auto">The problem comes when I add the <code class="notranslate">name_prefix</code> route:</p>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# config/routes.yaml
admin:
  name_prefix: admin_
  prefix: /admin
  resource: ../src/Controller/Admin
  type: annotation"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> config/routes.yaml</span>
<span class="pl-ent">admin</span>:
  <span class="pl-ent">name_prefix</span>: <span class="pl-s">admin_</span>
  <span class="pl-ent">prefix</span>: <span class="pl-s">/admin</span>
  <span class="pl-ent">resource</span>: <span class="pl-s">../src/Controller/Admin</span>
  <span class="pl-ent">type</span>: <span class="pl-s">annotation</span></pre></div>
<p dir="auto">The router debug gives the following output, and I can verify that the URLs are duplicated:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content=" -------------------------- ---------- -------- ------ ----------------------------------- 
  Name                       Method     Scheme   Host   Path                               
 -------------------------- ---------- -------- ------ ----------------------------------- 
  index                      ANY        ANY      ANY    /                                  
  login                      ANY        ANY      ANY    /login                             
  user_index                 GET        ANY      ANY    /user                              
  user_new                   GET|POST   ANY      ANY    /user/new                          
  user_show                  GET        ANY      ANY    /user/{id}                         
  user_edit                  GET|POST   ANY      ANY    /user/{id}/edit                    
  user_delete                DELETE     ANY      ANY    /user/{id}                         
  _twig_error_test           ANY        ANY      ANY    /_error/{code}.{_format}           
  _wdt                       ANY        ANY      ANY    /_wdt/{token}                      
  _profiler_home             ANY        ANY      ANY    /_profiler/                        
  _profiler_search           ANY        ANY      ANY    /_profiler/search                  
  _profiler_search_bar       ANY        ANY      ANY    /_profiler/search_bar              
  _profiler_phpinfo          ANY        ANY      ANY    /_profiler/phpinfo                 
  _profiler_search_results   ANY        ANY      ANY    /_profiler/{token}/search/results  
  _profiler_open_file        ANY        ANY      ANY    /_profiler/open                    
  _profiler                  ANY        ANY      ANY    /_profiler/{token}                 
  _profiler_router           ANY        ANY      ANY    /_profiler/{token}/router          
  _profiler_exception        ANY        ANY      ANY    /_profiler/{token}/exception       
  _profiler_exception_css    ANY        ANY      ANY    /_profiler/{token}/exception.css   
  admin_index                ANY        ANY      ANY    /admin/                            
  admin_login                ANY        ANY      ANY    /admin/login                       
  admin_user_index           GET        ANY      ANY    /admin/user                        
  admin_user_new             GET|POST   ANY      ANY    /admin/user/new                    
  admin_user_show            GET        ANY      ANY    /admin/user/{id}                   
  admin_user_edit            GET|POST   ANY      ANY    /admin/user/{id}/edit              
  admin_user_delete          DELETE     ANY      ANY    /admin/user/{id}                   
  admin_logout               ANY        ANY      ANY    /admin/logout                      
 -------------------------- ---------- -------- ------ ----------------------------------- "><pre class="notranslate"><code class="notranslate"> -------------------------- ---------- -------- ------ ----------------------------------- 
  Name                       Method     Scheme   Host   Path                               
 -------------------------- ---------- -------- ------ ----------------------------------- 
  index                      ANY        ANY      ANY    /                                  
  login                      ANY        ANY      ANY    /login                             
  user_index                 GET        ANY      ANY    /user                              
  user_new                   GET|POST   ANY      ANY    /user/new                          
  user_show                  GET        ANY      ANY    /user/{id}                         
  user_edit                  GET|POST   ANY      ANY    /user/{id}/edit                    
  user_delete                DELETE     ANY      ANY    /user/{id}                         
  _twig_error_test           ANY        ANY      ANY    /_error/{code}.{_format}           
  _wdt                       ANY        ANY      ANY    /_wdt/{token}                      
  _profiler_home             ANY        ANY      ANY    /_profiler/                        
  _profiler_search           ANY        ANY      ANY    /_profiler/search                  
  _profiler_search_bar       ANY        ANY      ANY    /_profiler/search_bar              
  _profiler_phpinfo          ANY        ANY      ANY    /_profiler/phpinfo                 
  _profiler_search_results   ANY        ANY      ANY    /_profiler/{token}/search/results  
  _profiler_open_file        ANY        ANY      ANY    /_profiler/open                    
  _profiler                  ANY        ANY      ANY    /_profiler/{token}                 
  _profiler_router           ANY        ANY      ANY    /_profiler/{token}/router          
  _profiler_exception        ANY        ANY      ANY    /_profiler/{token}/exception       
  _profiler_exception_css    ANY        ANY      ANY    /_profiler/{token}/exception.css   
  admin_index                ANY        ANY      ANY    /admin/                            
  admin_login                ANY        ANY      ANY    /admin/login                       
  admin_user_index           GET        ANY      ANY    /admin/user                        
  admin_user_new             GET|POST   ANY      ANY    /admin/user/new                    
  admin_user_show            GET        ANY      ANY    /admin/user/{id}                   
  admin_user_edit            GET|POST   ANY      ANY    /admin/user/{id}/edit              
  admin_user_delete          DELETE     ANY      ANY    /admin/user/{id}                   
  admin_logout               ANY        ANY      ANY    /admin/logout                      
 -------------------------- ---------- -------- ------ ----------------------------------- 
</code></pre></div>
<p dir="auto"><em>Originally posted by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/devnix/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/devnix">@devnix</a> in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="171062392" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/19612" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/19612/hovercard?comment_id=435630266&amp;comment_type=issue_comment" href="https://github.com/symfony/symfony/issues/19612#issuecomment-435630266">#19612 (comment)</a></em></p>
<p dir="auto">This issue is about discussion my DX initiative for optimization and generalization of symfony 2 functional testing mechanisms. I use this approach for about 2 years and i can provide corresponding PR if it receives positive feedback.</p>
<h1 dir="auto">Problem</h1>
<p dir="auto">For now all the bundles that contain functional tests need to describe test application kernel class to boot and run test application. These surrogate kernel classes look very similar to each other. You can find them not only inside base symfony's bundles: <a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php">FrameworkBundle</a>, <a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php">SecurityBundle</a>, <a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/TwigBundle/Tests/Functional/NoTemplatingEntryTest.php">TwigBundle</a>, but inside other bundles: <a href="https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Tests/Functional/app/AppKernel.php">FOSRestBundle</a>, <a href="https://github.com/FriendsOfSymfony/FOSOAuthServerBundle/blob/master/Tests/Functional/AppKernel.php">FOSOAuthServerBundle</a>. I can give you other examples if you want. Moreover developers often additionally have to deal with autoloading (See for example <a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php#L15-L36">here</a>).<br>
In my opinion such duplicating should be avoided. Instead it would be nice to have ability to <em>describe</em> what kind of test kernel we need in order to receive required kernel object from framework.</p>
<p dir="auto">Another drawback can be appeared if KERNEL_DIR env variable is used to point directory that contains 2 or more files suffixed with "Kernel" word. Imagine that my AppKernel extends some IntermediateKernel (which extends base Symfony\Component\HttpKernel\Kernel\Kernel) located in the same folder. Due to WebTestCase uses Finder to locate kernel file by '*Kernel.php' glob in such cases we actually can not know in advance what kernel exactly would be choosen (it can depend on OS and filesystem type).</p>
<h1 dir="auto">Proposal</h1>
<p dir="auto">Since every single bundle depends on framework-bundle we can place inside functionality to generate test kernels using user specified options.</p>
<p dir="auto">I propose to implement base implementation for test kernel class that implements all things that surrogate test kernels like listed above usually do (simplified):</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="/**
 * Kernel for functional / integration tests
 */
class BaseTestKernel extends Kernel implements TestKernelInterface
{
    protected $testCase;
    protected $rootConfig;
    protected $configDir;
    protected $rootDir;

    /**
     * Sets test kernel configuration 
     */
    public function setTestKernelConfiguration($testCase, $configDir, $rootConfig, $rootDir)
    {
         // initializing test configs
    }

    /**
     * Registers bundles for the test kernel
     */
    public function registerBundles()
    {
        $bundles     = array();
        $baseBundles = $this-&gt;getBaseBundles();
        if (file_exists($filename = $this-&gt;configDir . '/' . $this-&gt;testCase . '/bundles.php')) {
            $bundles = include $filename;
        }
        return array_merge($baseBundles, $bundles);
    }

    /**
     * {@inheritdoc}
     */
    public function getCacheDir()
    {
        return $this-&gt;getTempAppDir().'/cache/'.$this-&gt;environment;
    }

    /**
     * {@inheritdoc}
     */
    public function getLogDir()
    {
        return $this-&gt;getTempAppDir().'/logs';
    }

    /**
     * {@inheritdoc}
     */
    public function getTempAppDir()
    {
        return sys_get_temp_dir().'/'.$this-&gt;testCase;
    }

    /**
     * {@inheritdoc}
     */
    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        $loader-&gt;load($this-&gt;rootConfig);
    }

    /**
     * {@inheritDoc}
     */
    public function serialize()
    {
        // serializing test kernel
    }

    /**
     * {@inheritdoc}
     */
    public function unserialize($str)
    {
       // unserializing test kernel
    }


    /**
     * Returns base bundle list
     *
     * @return array
     */
    protected function getBaseBundles()
    {
        return array(new \Symfony\Bundle\FrameworkBundle\FrameworkBundle());
    }

    /**
     * {@inheritDoc}
     */
    protected function getKernelParameters()
    {
        $parameters = parent::getKernelParameters();
        $parameters['kernel.test_case']  = $this-&gt;testCase;

        return $parameters;
    }
}"><pre class="notranslate"><span class="pl-c">/**</span>
<span class="pl-c"> * Kernel for functional / integration tests</span>
<span class="pl-c"> */</span>
<span class="pl-k">class</span> <span class="pl-v">BaseTestKernel</span> <span class="pl-k">extends</span> <span class="pl-v">Kernel</span> <span class="pl-k">implements</span> <span class="pl-v">TestKernelInterface</span>
{
    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>testCase</span>;
    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>rootConfig</span>;
    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>configDir</span>;
    <span class="pl-k">protected</span> <span class="pl-c1"><span class="pl-c1">$</span>rootDir</span>;

    <span class="pl-c">/**</span>
<span class="pl-c">     * Sets test kernel configuration </span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">setTestKernelConfiguration</span>(<span class="pl-s1"><span class="pl-c1">$</span>testCase</span>, <span class="pl-s1"><span class="pl-c1">$</span>configDir</span>, <span class="pl-s1"><span class="pl-c1">$</span>rootConfig</span>, <span class="pl-s1"><span class="pl-c1">$</span>rootDir</span>)
    {
         <span class="pl-c">// initializing test configs</span>
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * Registers bundles for the test kernel</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">registerBundles</span>()
    {
        <span class="pl-s1"><span class="pl-c1">$</span>bundles</span>     = <span class="pl-en">array</span>();
        <span class="pl-s1"><span class="pl-c1">$</span>baseBundles</span> = <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getBaseBundles</span>();
        <span class="pl-k">if</span> (file_exists(<span class="pl-s1"><span class="pl-c1">$</span>filename</span> = <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">configDir</span> . <span class="pl-s">'/'</span> . <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">testCase</span> . <span class="pl-s">'/bundles.php'</span>)) {
            <span class="pl-s1"><span class="pl-c1">$</span>bundles</span> = <span class="pl-k">include</span> <span class="pl-s1"><span class="pl-c1">$</span>filename</span>;
        }
        <span class="pl-k">return</span> array_merge(<span class="pl-s1"><span class="pl-c1">$</span>baseBundles</span>, <span class="pl-s1"><span class="pl-c1">$</span>bundles</span>);
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritdoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">getCacheDir</span>()
    {
        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getTempAppDir</span>().<span class="pl-s">'/cache/'</span>.<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">environment</span>;
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritdoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">getLogDir</span>()
    {
        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-en">getTempAppDir</span>().<span class="pl-s">'/logs'</span>;
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritdoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">getTempAppDir</span>()
    {
        <span class="pl-k">return</span> sys_get_temp_dir().<span class="pl-s">'/'</span>.<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">testCase</span>;
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritdoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">registerContainerConfiguration</span>(<span class="pl-smi"><span class="pl-smi">LoaderInterface</span></span> <span class="pl-s1"><span class="pl-c1">$</span>loader</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span>loader</span>-&gt;<span class="pl-en">load</span>(<span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">rootConfig</span>);
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritDoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">serialize</span>()
    {
        <span class="pl-c">// serializing test kernel</span>
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritdoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">unserialize</span>(<span class="pl-s1"><span class="pl-c1">$</span>str</span>)
    {
       <span class="pl-c">// unserializing test kernel</span>
    }


    <span class="pl-c">/**</span>
<span class="pl-c">     * Returns base bundle list</span>
<span class="pl-c">     *</span>
<span class="pl-c">     * @return array</span>
<span class="pl-c">     */</span>
    <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getBaseBundles</span>()
    {
        <span class="pl-k">return</span> <span class="pl-en">array</span>(<span class="pl-k">new</span> \<span class="pl-v">Symfony</span>\<span class="pl-v">Bundle</span>\<span class="pl-v">FrameworkBundle</span>\<span class="pl-v">FrameworkBundle</span>());
    }

    <span class="pl-c">/**</span>
<span class="pl-c">     * {@inheritDoc}</span>
<span class="pl-c">     */</span>
    <span class="pl-k">protected</span> <span class="pl-k">function</span> <span class="pl-en">getKernelParameters</span>()
    {
        <span class="pl-s1"><span class="pl-c1">$</span>parameters</span> = <span class="pl-smi">parent</span>::<span class="pl-en">getKernelParameters</span>();
        <span class="pl-s1"><span class="pl-c1">$</span>parameters</span>[<span class="pl-s">'kernel.test_case'</span>]  = <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">testCase</span>;

        <span class="pl-k">return</span> <span class="pl-s1"><span class="pl-c1">$</span>parameters</span>;
    }
}</pre></div>
<p dir="auto">This kernel class should be instantiated inside <a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php#L156">KernelTestCase::createKernel</a> method upon the options ($testCase, $configDir, $rootConfig, $rootDir, $env, $debug) passed to the <a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php#L31">createClient</a> method.<br>
Framework bundle also can provide some default test application configuration that can be extended in the custom bundles and specified using $rootConfig option.<br>
So this approach can significantly reduce duplication of the code that generates test kernels across the bundles and simultaneously provide the flexibility in configuring test kernel. We also can have more then one simply configured instances of test kernel inside bundle test suite to run tests in different configurations (different bundle config, different routing etc).<br>
Also i think we should provide ability to extend TestCase class to replace used base test kernel class with another one (apparently implementing base TestKernelInterface).</p>
<p dir="auto">Moreover it can be reasonable to allow setting environment variable (or php constant using phpunit.xml) KERNEL_CLASS that can hold FQCN of <em>any</em> kernel class (not only test kernel that implements TestKernelInterface) that can be used by KernelTestCase as a replacement of base test kernel class (BaseTestKernel in default case) to construct real kernel with main params - $environment and $debug. In this case we can simply run bundle's functional test cases in any application environment by replacing our pre-configured test kernels with real application kernel transforming our functional tests to integration ones.</p>