设置 CakePHP 3 插件测试 [英] Setting up CakePHP 3 Plugin testing

查看:38
本文介绍了设置 CakePHP 3 插件测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 bin/cake bake plugin PluginName 来创建插件.部分原因是它会创建 phpunit.xml.dist,但 bake 不会创建所需的文件夹结构或 tests/bootstrap.php 文件.

I've used bin/cake bake plugin PluginName to create a plugin. Part of it is that it creates phpunit.xml.dist, but bake doesn't create the folder structure or tests/bootstrap.php file that's required.

问题

我在运行 phpunit 时收到未执行测试"消息:

I get a "No tests executed" message when I run phpunit:

$ phpunit
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.

Time: 239 ms, Memory: 4.50Mb

No tests executed!

背景信息

我在 tests/TestCase 下的插件文件夹中创建了我的测试.我不认为它们是问题,但我会在最后发布它们.

I've created my tests in my plugin folder under tests/TestCase. I don't think they are the issue, but I'll post them at the end.

我正在使用默认的 phpunit.xml.dist 文件,并且我将它用于 tests/bootstrap.php:

I'm using the default phpunit.xml.dist file, and I'm using this for tests/bootstrap.php:

$findRoot = function ($root) {
    do {
        $lastRoot = $root;
        $root = dirname($root);
        if (is_dir($root . '/vendor/cakephp/cakephp')) {
            return $root;
        }
    } while ($root !== $lastRoot);
    throw new Exception("Cannot find the root of the application, unable to run tests");
};
$root = $findRoot(__FILE__);
unset($findRoot);
chdir($root);

define('ROOT', $root);
define('APP_DIR', 'App');
define('WEBROOT_DIR', 'webroot');
define('APP', ROOT . '/tests/App/');
define('CONFIG', ROOT . '/tests/config/');
define('WWW_ROOT', ROOT . DS . WEBROOT_DIR . DS);
define('TESTS', ROOT . DS . 'tests' . DS);
define('TMP', ROOT . DS . 'tmp' . DS);
define('LOGS', TMP . 'logs' . DS);
define('CACHE', TMP . 'cache' . DS);
define('CAKE_CORE_INCLUDE_PATH', ROOT . '/vendor/cakephp/cakephp');
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
define('CAKE', CORE_PATH . 'src' . DS);

require ROOT . '/vendor/autoload.php';
require CORE_PATH . 'config/bootstrap.php';

单元测试

这存在于 tests/TestCase/Color.php

<?php

namespace ContrastTestCase;

use CakeTestSuiteTestCase;
use ContrastTextColor;

/**
 * Contrast Text Color tests
 */
class TextColorTest extends TestCase
{
    /**
     * @test
     * @return void
     */
    public function testShouldHandleVarietyOfColors()
    {
        # Returns black
        $this->assertEquals(Color::getBlackWhiteContrast('#FFFFFF'), 'black');

        // Why won't you fail??
        $this->assertEquals(true, false);
    }

推荐答案

首要任务

基本命名空间应该是 ContrastTest,这也是 bake 应该添加到应用程序 composer.json 文件 autoloadautoload-dev 部分,以及烘焙插件 composer.json 文件.如果您拒绝烘焙以编辑您的 composer.json 文件,则应手动添加自动加载条目

First things first

The base namespace should be ContrastTest, which is also what bake should have added to your applications composer.json files autoload and autoload-dev sections, as well as to the baked plugins composer.json file. In case you denied bake to edit yout composer.json file, you should add the autoload entry manually

"autoload": {
    "psr-4": {
        // ...
        "Contrast\": "./plugins/Contrast/src"
    }
},
"autoload-dev": {
    "psr-4": {
        // ...
        "Contrast\Test\": "./plugins/Contrast/tests"
    }
},

并重新转储自动加载器

$ composer dump-autoload

因此,示例测试的命名空间应该是 ContrastTestTestCase.

So the namespace for your example test should be ContrastTestTestCase.

为了让 PHPUnit 识别它们,测试文件也需要以 Test 为后缀.为了使文件能够自动加载,你应该坚持 PSR-4,即文件应该与类同名,即你的测试文件应该命名为 TextColorTest.php,而不是 <代码>Color.php.

Also test files need to be postfixed with Test in order for PHPUnit to recognize them. And in order for the files to be autoloadable, you should stick to PSR-4, ie the files should have the same name as the class, ie your test file should be named TextColorTest.php, not Color.php.

当测试一个插件作为应用程序的一部分时,插件测试中不一定需要引导文件(bake 应该,实际上确实会生成一个),因为您可以使用应用程序的配置运行它们,它有一个测试引导文件 (tests/bootstrap.php),其中包含您的应用程序引导文件 (config/bootstrap.php).

When testing a plugin as a part on an application, there is not necessarily a need for a bootstrap file in the plugin tests (bake should, actually does generate one though), as you could run them with the configuration of your application, which has a test bootstrap file (tests/bootstrap.php) that includes your applications bootstrap file (config/bootstrap.php).

因此,测试将从您的应用程序基础文件夹中运行,并且您必须传递插件路径,例如

Consequently the tests would be run from your applications base folder, and you'd have to pass the plugin path, like

$ vendor/bin/phpunit plugins/Contrast

或者你会在你的应用程序主 phpunit 配置文件中添加一个额外的插件测试套件,其中显示 <!-- 添加你的插件套件 -->

or you'd add an additional plugin testsuite in your apps main phpunit configuration file, where it says <!-- Add your plugin suites -->

<testsuite name="Contrast Test Suite">
    <directory>./plugins/Contrast/tests/TestCase</directory>
</testsuite>

这样插件测试将与您的应用测试一起运行.

That way the plugin tests will be run together with your app tests.

最后,如果存在适当的引导文件,您还可以从插件目录运行测试.默认的当前看起来像:

Finally, you can also run the tests from the plugin directory, given that a proper bootstrap file exists. The default one currently looks like:

<?php
/**
 * Test suite bootstrap for Contrast.
 *
 * This function is used to find the location of CakePHP whether CakePHP
 * has been installed as a dependency of the plugin, or the plugin is itself
 * installed as a dependency of an application.
 */
$findRoot = function ($root) {
    do {
        $lastRoot = $root;
        $root = dirname($root);
        if (is_dir($root . '/vendor/cakephp/cakephp')) {
            return $root;
        }
    } while ($root !== $lastRoot);

    throw new Exception("Cannot find the root of the application, unable to run tests");
};
$root = $findRoot(__FILE__);
unset($findRoot);

chdir($root);
require $root . '/config/bootstrap.php';

另见

食谱 >测试 > 为插件创建测试

当以独立的方式开发插件时,这就是你真正需要一个设置环境的引导文件的时候,这就是使用 bake 生成的插件 composer.json 文件的地方.默认情况下,后者看起来像

When developing plugins in a standalone fashion, this is when you really need a bootstrap file that sets up the environment, and this is where the plugins composer.json file generated by bake is being used. By default the latter would look like

{
    "name": "your-name-here/Contrast",
    "description": "Contrast plugin for CakePHP",
    "type": "cakephp-plugin",
    "require": {
        "php": ">=5.4.16",
        "cakephp/cakephp": "~3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "*"
    },
    "autoload": {
        "psr-4": {
            "Contrast\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Contrast\Test\": "tests",
            "Cake\Test\": "./vendor/cakephp/cakephp/tests"
        }
    }
}

烘焙插件时生成的测试引导文件不能开箱即用,因为它只会尝试加载插件的 config/bootstrap.php 文件,这默认情况下甚至不存在.

The test bootstrap file generated when baking a plugin doesn't work out of the box, as all it would do would be trying to load the config/bootstrap.php file of your plugin, which by default doesn't even exist.

测试引导文件需要做什么当然取决于插件在做什么,但至少应该这样做

What the test bootstrap file needs to do depends on what the plugin is doing of course, but at the very least it should

  • 定义核心使用的基本常量和配置
  • 需要作曲家自动加载器
  • 需要 CakePHP 核心引导文件
  • 并加载/注册您的插件.

出于示例目的,这是一个 tests/bootstrap.php 示例,其中包含当前 cakephp/app 应用程序模板所做的副本,即它基本上配置了一个完整的应用程序环境(应用程序定义在 tests/TestApp 文件夹中):

For example purposes, here's a tests/bootstrap.php example with a copy of what the current cakephp/app application template does, ie it basically configures a full application environment (with the application defined to be found in the tests/TestApp folder):

// from `config/paths.php`

if (!defined('DS')) {
    define('DS', DIRECTORY_SEPARATOR);
}
define('ROOT', dirname(__DIR__));
define('APP_DIR', 'test_app');
define('APP', ROOT . DS . 'tests' . DS . APP_DIR . DS);
define('CONFIG', ROOT . DS . 'config' . DS);
define('WWW_ROOT', APP . 'webroot' . DS);
define('TESTS', ROOT . DS . 'tests' . DS);
define('TMP', ROOT . DS . 'tmp' . DS);
define('LOGS', TMP . 'logs' . DS);
define('CACHE', TMP . 'cache' . DS);
define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'vendor' . DS . 'cakephp' . DS . 'cakephp');
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
define('CAKE', CORE_PATH . 'src' . DS);


// from `config/app.default.php` and `config/bootstrap.php`

use CakeCacheCache;
use CakeConsoleConsoleErrorHandler;
use CakeCoreApp;
use CakeCoreConfigure;
use CakeCoreConfigureEnginePhpConfig;
use CakeCorePlugin;
use CakeDatabaseType;
use CakeDatasourceConnectionManager;
use CakeErrorErrorHandler;
use CakeLogLog;
use CakeMailerEmail;
use CakeNetworkRequest;
use CakeRoutingDispatcherFactory;
use CakeUtilityInflector;
use CakeUtilitySecurity;

require ROOT . DS . 'vendor' . DS . 'autoload.php';
require CORE_PATH . 'config' . DS . 'bootstrap.php';

$config = [
    'debug' => true,

    'App' => [
        'namespace' => 'App',
        'encoding' => env('APP_ENCODING', 'UTF-8'),
        'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_US'),
        'base' => false,
        'dir' => 'src',
        'webroot' => 'webroot',
        'wwwRoot' => WWW_ROOT,
        'fullBaseUrl' => false,
        'imageBaseUrl' => 'img/',
        'cssBaseUrl' => 'css/',
        'jsBaseUrl' => 'js/',
        'paths' => [
            'plugins' => [ROOT . DS . 'plugins' . DS],
            'templates' => [APP . 'Template' . DS],
            'locales' => [APP . 'Locale' . DS],
        ],
    ],

    'Asset' => [
        // 'timestamp' => true,
    ],

    'Security' => [
        'salt' => env('SECURITY_SALT', '__SALT__'),
    ],

    'Cache' => [
        'default' => [
            'className' => 'File',
            'path' => CACHE,
            'url' => env('CACHE_DEFAULT_URL', null),
        ],

        '_cake_core_' => [
            'className' => 'File',
            'prefix' => 'myapp_cake_core_',
            'path' => CACHE . 'persistent/',
            'serialize' => true,
            'duration' => '+2 minutes',
            'url' => env('CACHE_CAKECORE_URL', null),
        ],

        '_cake_model_' => [
            'className' => 'File',
            'prefix' => 'myapp_cake_model_',
            'path' => CACHE . 'models/',
            'serialize' => true,
            'duration' => '+2 minutes',
            'url' => env('CACHE_CAKEMODEL_URL', null),
        ],
    ],

    'Error' => [
        'errorLevel' => E_ALL & ~E_DEPRECATED,
        'exceptionRenderer' => 'CakeErrorExceptionRenderer',
        'skipLog' => [],
        'log' => true,
        'trace' => true,
    ],

    'EmailTransport' => [
        'default' => [
            'className' => 'Mail',
            // The following keys are used in SMTP transports
            'host' => 'localhost',
            'port' => 25,
            'timeout' => 30,
            'username' => 'user',
            'password' => 'secret',
            'client' => null,
            'tls' => null,
            'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
        ],
    ],

    'Email' => [
        'default' => [
            'transport' => 'default',
            'from' => 'you@localhost',
            //'charset' => 'utf-8',
            //'headerCharset' => 'utf-8',
        ],
    ],

    'Datasources' => [
        'test' => [
            'className' => 'CakeDatabaseConnection',
            'driver' => 'CakeDatabaseDriverMysql',
            'persistent' => false,
            'host' => 'localhost',
            //'port' => 'non_standard_port_number',
            'username' => 'my_app',
            'password' => 'secret',
            'database' => 'test_myapp',
            'encoding' => 'utf8',
            'timezone' => 'UTC',
            'cacheMetadata' => true,
            'quoteIdentifiers' => false,
            'log' => false,
            //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
            'url' => env('DATABASE_TEST_URL', null),
        ],
    ],

    'Log' => [
        'debug' => [
            'className' => 'CakeLogEngineFileLog',
            'path' => LOGS,
            'file' => 'debug',
            'levels' => ['notice', 'info', 'debug'],
            'url' => env('LOG_DEBUG_URL', null),
        ],
        'error' => [
            'className' => 'CakeLogEngineFileLog',
            'path' => LOGS,
            'file' => 'error',
            'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
            'url' => env('LOG_ERROR_URL', null),
        ],
    ],

    'Session' => [
        'defaults' => 'php',
    ],
];
Configure::write($config);

date_default_timezone_set('UTC');
mb_internal_encoding(Configure::read('App.encoding'));
ini_set('intl.default_locale', Configure::read('App.defaultLocale'));

Cache::config(Configure::consume('Cache'));
ConnectionManager::config(Configure::consume('Datasources'));
Email::configTransport(Configure::consume('EmailTransport'));
Email::config(Configure::consume('Email'));
Log::config(Configure::consume('Log'));
Security::salt(Configure::consume('Security.salt'));

DispatcherFactory::add('Asset');
DispatcherFactory::add('Routing');
DispatcherFactory::add('ControllerFactory');

Type::build('time')
    ->useImmutable()
    ->useLocaleParser();
Type::build('date')
    ->useImmutable()
    ->useLocaleParser();
Type::build('datetime')
    ->useImmutable()
    ->useLocaleParser();


// finally load/register the plugin using a custom path

Plugin::load('Contrast', ['path' => ROOT]);

为了使类可以从测试应用程序文件夹中自动加载,您必须在 composer.json 文件中添加相应的自动加载条目(并再次重新转储自动加载器),例如:

In order for classes to be autoloadable from the test application folder, you'd have to add a corresponding autoload entry in your composer.json file (and again re-dump the autoloader), like:

    "autoload-dev": {
        "psr-4": {
            "Contrast\Test\": "tests",
            "Contrast\TestApp\": "tests/test_app/src", // < here we go
            "Cake\Test\": "./vendor/cakephp/cakephp/tests"
        }
    }

现在使用 bake 创建插件,配置环境并安装 CakePHP 和 PHPUnit 依赖项,您应该能够像使用应用程序一样运行测试,即

So now with the plugin been created using bake, the environment configured and the CakePHP and PHPUnit dependencies installed, you should be able to run your tests as you would with an application, ie

$ vendor/bin/phpunit

这篇关于设置 CakePHP 3 插件测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆