Yii2 扩展开发测试环境指南
Yii2 testing environment guidelines for extension development
我正在开发 Yii 2 public (MIT) 扩展来改变一些 yii\web\View
行为(缩小、合并和许多其他优化)。
我可以轻松做到。但我真的很想为它编写尽可能多的测试(codeception)。这是我很疑惑的地方。
我已经有一些 unit 测试(例如:测试特定的缩小,或返回合并的缩小结果)。但我想测试整个结果以及我的扩展和使用它的 Yii2 web 应用程序之间的最终集成。
我只是想要一些关于此过程的指南:
我的扩展中是否应该有一个真正的(完整的)应用程序用于测试目的?如果是这样,它应该是 'installed' inside tests dir?
您会使用功能测试吗? (我认为是,因为 View
会 在 AssetBundles
中找到 文件, 合并 和 minify 他们,将结果发布为单个文件,并在视图中用新的 url(即优化的资产 url)替换资产的 url;
你能提供一些非常基本的东西吗examples/guidelines?
我只想强调我不打算让你做我的测试工作,我真的很想学习怎么做.这就是为什么我真的会非常感谢任何提示。
非常感谢。
我自己的指导方针
好的,我已经根据 yii2-smarty 中的测试找到了自己的方法。
因此,这些是使用 phpunit:
测试您自己的 Yii2 扩展开发的指南
1) tests/bootstrap.php:
// ensure we get report on all possible php errors
error_reporting(-1);
define('YII_ENABLE_ERROR_HANDLER', false);
define('YII_DEBUG', true);
$_SERVER['SCRIPT_NAME'] = '/' . __DIR__;
$_SERVER['SCRIPT_FILENAME'] = __FILE__;
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
//optionals
Yii::setAlias('@testsBasePathOrWhateverYouWant', __DIR__);
Yii::setAlias('@slinstj/MyExtensionAlias', dirname(__DIR__));
2) 创建一个 tests/TestCase 基础 class 扩展 \PHPUnit_Framework_TestCase
:
namespace slinstj\MyExtension\tests;
use yii\di\Container;
/**
* This is the base class for all yii framework unit tests.
*/
abstract class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* Clean up after test.
* By default the application created with [[mockApplication]] will be destroyed.
*/
protected function tearDown()
{
parent::tearDown();
$this->destroyApplication();
}
/**
* Populates Yii::$app with a new application
* The application will be destroyed on tearDown() automatically.
* @param array $config The application configuration, if needed
* @param string $appClass name of the application class to create
*/
protected function mockApplication($config = [], $appClass = '\yii\console\Application')
{
new $appClass(ArrayHelper::merge([
'id' => 'testapp',
'basePath' => __DIR__,
'vendorPath' => dirname(__DIR__) . '/vendor',
], $config));
}
protected function mockWebApplication($config = [], $appClass = '\yii\web\Application')
{
new $appClass(ArrayHelper::merge([
'id' => 'testapp',
'basePath' => __DIR__,
'vendorPath' => dirname(__DIR__) . '/vendor',
'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ .'/index.php',
'scriptUrl' => '/index.php',
],
]
], $config));
}
/**
* Destroys application in Yii::$app by setting it to null.
*/
protected function destroyApplication()
{
Yii::$app = null;
Yii::$container = new Container();
}
protected function debug($data)
{
return fwrite(STDERR, print_r($data, TRUE));
}
}
3) 创建你的测试 classes extending TestCase
:
namespace slinstj\MyExtension\tests;
use yii\web\AssetManager;
use slinstj\MyExtension\View;
use Yii;
/**
* Generated by PHPUnit_SkeletonGenerator on 2015-10-30 at 17:45:03.
*/
class ViewTest extends TestCase
{
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
parent::setUp();
$this->mockWebApplication();
}
public function testSomething()
{
$view = $this->mockView();
$content = $view->renderFile('@someAlias/views/index.php', ['data' => 'Hello World!']);
$this->assertEquals(1, preg_match('#something#', $content), 'Html view does not contain "something": ' . $content);
}
//other tests...
/**
* @return View
*/
protected function mockView()
{
return new View([
'someConfig' => 'someValue',
'assetManager' => $this->mockAssetManager(),
]);
}
protected function mockAssetManager()
{
$assetDir = Yii::getAlias('@the/path/to/assets');
if (!is_dir($assetDir)) {
mkdir($assetDir, 0777, true);
}
return new AssetManager([
'basePath' => $assetDir,
'baseUrl' => '/assets',
]);
}
protected function findByRegex($regex, $content, $match = 1)
{
$matches = [];
preg_match($regex, $content, $matches);
return $matches[$match];
}
}
就是这样!此代码框架高度基于 yii2-smaty/tests 代码。希望能帮助到你(还有我的进一步需要)。
这种方法有效,但我不得不做一些小的调整:
如果您正在开发扩展(在 /vendor/you/extension 目录中)并且 bootstrap.php 文件在测试目录中,自动加载器和 yii base class 的路径很可能是错误的。更好的是:
require_once(__DIR__ . '/../../../autoload.php');
require_once(__DIR__ . '/../../../yiisoft/yii2/Yii.php');
我测试了一个需要应用程序对象的验证器 class。我只是在 bootstrap 文件中创建了一个控制台应用程序(附加到文件末尾):
$config = require(__DIR__ . '/../../../../config/console.php');
$application = new yii\console\Application($config);
我正在开发 Yii 2 public (MIT) 扩展来改变一些 yii\web\View
行为(缩小、合并和许多其他优化)。
我可以轻松做到。但我真的很想为它编写尽可能多的测试(codeception)。这是我很疑惑的地方。
我已经有一些 unit 测试(例如:测试特定的缩小,或返回合并的缩小结果)。但我想测试整个结果以及我的扩展和使用它的 Yii2 web 应用程序之间的最终集成。
我只是想要一些关于此过程的指南:
我的扩展中是否应该有一个真正的(完整的)应用程序用于测试目的?如果是这样,它应该是 'installed' inside tests dir?
您会使用功能测试吗? (我认为是,因为
View
会 在AssetBundles
中找到 文件, 合并 和 minify 他们,将结果发布为单个文件,并在视图中用新的 url(即优化的资产 url)替换资产的 url;你能提供一些非常基本的东西吗examples/guidelines?
我只想强调我不打算让你做我的测试工作,我真的很想学习怎么做.这就是为什么我真的会非常感谢任何提示。
非常感谢。
我自己的指导方针
好的,我已经根据 yii2-smarty 中的测试找到了自己的方法。
因此,这些是使用 phpunit:
测试您自己的 Yii2 扩展开发的指南1) tests/bootstrap.php:
// ensure we get report on all possible php errors
error_reporting(-1);
define('YII_ENABLE_ERROR_HANDLER', false);
define('YII_DEBUG', true);
$_SERVER['SCRIPT_NAME'] = '/' . __DIR__;
$_SERVER['SCRIPT_FILENAME'] = __FILE__;
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
//optionals
Yii::setAlias('@testsBasePathOrWhateverYouWant', __DIR__);
Yii::setAlias('@slinstj/MyExtensionAlias', dirname(__DIR__));
2) 创建一个 tests/TestCase 基础 class 扩展 \PHPUnit_Framework_TestCase
:
namespace slinstj\MyExtension\tests;
use yii\di\Container;
/**
* This is the base class for all yii framework unit tests.
*/
abstract class TestCase extends \PHPUnit_Framework_TestCase
{
/**
* Clean up after test.
* By default the application created with [[mockApplication]] will be destroyed.
*/
protected function tearDown()
{
parent::tearDown();
$this->destroyApplication();
}
/**
* Populates Yii::$app with a new application
* The application will be destroyed on tearDown() automatically.
* @param array $config The application configuration, if needed
* @param string $appClass name of the application class to create
*/
protected function mockApplication($config = [], $appClass = '\yii\console\Application')
{
new $appClass(ArrayHelper::merge([
'id' => 'testapp',
'basePath' => __DIR__,
'vendorPath' => dirname(__DIR__) . '/vendor',
], $config));
}
protected function mockWebApplication($config = [], $appClass = '\yii\web\Application')
{
new $appClass(ArrayHelper::merge([
'id' => 'testapp',
'basePath' => __DIR__,
'vendorPath' => dirname(__DIR__) . '/vendor',
'components' => [
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ .'/index.php',
'scriptUrl' => '/index.php',
],
]
], $config));
}
/**
* Destroys application in Yii::$app by setting it to null.
*/
protected function destroyApplication()
{
Yii::$app = null;
Yii::$container = new Container();
}
protected function debug($data)
{
return fwrite(STDERR, print_r($data, TRUE));
}
}
3) 创建你的测试 classes extending TestCase
:
namespace slinstj\MyExtension\tests;
use yii\web\AssetManager;
use slinstj\MyExtension\View;
use Yii;
/**
* Generated by PHPUnit_SkeletonGenerator on 2015-10-30 at 17:45:03.
*/
class ViewTest extends TestCase
{
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
parent::setUp();
$this->mockWebApplication();
}
public function testSomething()
{
$view = $this->mockView();
$content = $view->renderFile('@someAlias/views/index.php', ['data' => 'Hello World!']);
$this->assertEquals(1, preg_match('#something#', $content), 'Html view does not contain "something": ' . $content);
}
//other tests...
/**
* @return View
*/
protected function mockView()
{
return new View([
'someConfig' => 'someValue',
'assetManager' => $this->mockAssetManager(),
]);
}
protected function mockAssetManager()
{
$assetDir = Yii::getAlias('@the/path/to/assets');
if (!is_dir($assetDir)) {
mkdir($assetDir, 0777, true);
}
return new AssetManager([
'basePath' => $assetDir,
'baseUrl' => '/assets',
]);
}
protected function findByRegex($regex, $content, $match = 1)
{
$matches = [];
preg_match($regex, $content, $matches);
return $matches[$match];
}
}
就是这样!此代码框架高度基于 yii2-smaty/tests 代码。希望能帮助到你(还有我的进一步需要)。
这种方法有效,但我不得不做一些小的调整:
如果您正在开发扩展(在 /vendor/you/extension 目录中)并且 bootstrap.php 文件在测试目录中,自动加载器和 yii base class 的路径很可能是错误的。更好的是:
require_once(__DIR__ . '/../../../autoload.php'); require_once(__DIR__ . '/../../../yiisoft/yii2/Yii.php');
我测试了一个需要应用程序对象的验证器 class。我只是在 bootstrap 文件中创建了一个控制台应用程序(附加到文件末尾):
$config = require(__DIR__ . '/../../../../config/console.php'); $application = new yii\console\Application($config);