使用 Fat-Free 框架进行单元测试
Unit Testing with Fat-Free-Framework
有没有办法在我的 index.php 文件中有一个包含 indexTest.php 的测试文件夹的情况下使用 PHPUnit?
fat-free 指南给出了模拟路由请求和 POSTS 的代码片段。如果我直接在我的测试文件中生成具有任何功能的路由,我只能设法让这样的测试工作。
我想用令牌模拟一条路线,允许它从 index.php 中的路线 运行 并通过控制器并测试应由 [=23 设置的 f3 变量=]路线。
<?php
class indexTest extends \PHPUnit_Framework_TestCase
{
public function test()
{
$f3 = Base::instance();
// Don't write to STDOUT
$f3->set('QUIET', true);
$f3->route('GET /path', function(){ echo 'TEXT'; });
$this->assertNull($f3->mock('GET /path'));
$this->assertSame('TEXT', $f3->get('RESPONSE'));
$f3->route('GET /verify/@answer/@value',
function($f3, $params){
$errors = array();
$answer = $params['answer'];
$value = $params['value'];
$prefix = substr($answer, 0, 3); //pre, ans, pos
$id = (int)substr($answer, 3); //question id number (1, 2, 3, 4)
//$value is the input value from user
$result = check_id($prefix, $id, $value);
if($result !== true){
$errors[] = $result;
}
$f3->set('errors', $errors);
return $errors;
});
function check_id($prefix, $id, $value)
{
if($prefix == 'pre' || $prefix == 'pos'){
if($value <= 0 || $value > 180 || $value === NULL){
echo 'The input value of ' . $prefix . $id . ' question was out of bounds';
return 'The input value of ' . $prefix . $id . ' question was out of bounds';
}else{
return true;
}
}else if($prefix == 'ans'){
if($value < 0 || $value > 10 || $value === NULL){
echo 'The value of quiz ans' + $id + ' was out of bounds';
return 'The value of quiz ans' + $id + ' was out of bounds';
}else{
return true;
}
}else {
return 'The prefix does not match';
}
}
$this->assertNotNull($f3->mock('GET /verify/ans1/8'));
$this->assertEmpty($f3->get('RESPONSE')[0]);
$this->assertNotNull($f3->mock('GET /verify/dsk4/6'));
$this->assertSame('6', $f3->get('PARAMS.value'));
$this->assertSame('dsk4', $f3->get('PARAMS.answer'));
$this->assertEmpty($f3->get('RESPONSE')[0]);
$this->assertNotNull($f3->mock('GET /verify/pre4/250'));
$this->assertSame('The input value of pre4 question was out of bounds', $f3->get('errors')[0]);
$this->assertNotSame('pre4', $f3->get('PARAMS.answer'));
$f3->set('QUIET',FALSE); // allow test results to be shown later
$f3->clear('ERROR'); // clear any errors
}
}
我不想像这样声明整条路线,也许我完全错了,这是不可能的?上面的代码有效 运行ning vendor/bin/phpunit。在这方面很难找到相关的例子和教程。
简答
将您的控制器代码与 bootstrapping 和路由代码分开
在您的环境中重复使用路由配置,例如网站、CLI 和测试环境
在你的测试中使用Base->mock()
来模拟之前定义的路由
不要在测试环境中执行Base->run()
长答案
早就想写一篇测试F3路线的文章了,但由于时间不够,我就在这里提几点:
创建一个定义路由的可重用文件(例如 routes.php
文件或具有路由定义的 INI
文件)
加载运行测试代码之前的路由。这可以通过 PHPUnit 的自定义 bootstrap 文件轻松完成(--bootstrap <FILE>
或使用 PHPUnit 配置中的相应指令)。
编写 PHPUnit 测试
示例
以下示例改编自我的 GitHub Gist:
bootstrap-website.php
<?php
$f3 = Base::instance();
require 'bootstrap-shared.php';
// [Custom rules only for the website here]
require 'routes.php';
$f3->run();
bootstrap-test.php
<?php
$f3 = Base::instance();
require 'bootstrap-shared.php';
// [Custom rules only for testing environment here]
$f3->set('QUIET', true);
$f3->set('APP.TEST', true);
require 'routes.php';
routes.php
<?php
/**
* @var $f3 Base
*/
$f3->route('GET /path', function(){ echo 'TEXT'; });
ExampleTest.php
class ExampleTest extends PHPUnit_Framework_TestCase {
public function test() {
// Could also be provided by a custom base TestCase.
$f3 = Base::instance();
$this->assertNull($f3->mock('GET /path'));
$this->assertSame('TEXT', $f3->get('RESPONSE'));
}
}
一些注意事项:
bootstrap-test.php
是 PHPUnit
的自定义 bootstrapping 文件
bootstrap-website.php
是网站的 bootstrapping 文件
bootstrap-shared.php
包含所有环境共享的信息。该文件可能包含路由信息。我在例子中分离了路由信息:routes.php
ExampleTest.php
是一个常规的 PHPUnit 测试
$f3->set('QUIET', true);
片段应添加到自定义 bootstrap 文件中。引入一个变量表明应用程序处于测试模式 运行 也是一个好主意,例如 $f3->set('APP.TEST', true)
F3 不会清除 tests/mocks 之间的变量。您可以在 运行 测试之前存储原始状态,然后在 PHPUnit 的 setUp()
方法中恢复状态
它 也足以只收集应该可用于呈现的数据,而不是呈现页面。在这种情况下,在您的视图中使用引入的 APP.TEST
变量来跳过渲染
稍后回答更新的注释
ini_set('error_log','./phpunit/error.log')
$f3->set('ONERROR',function(){});
有没有办法在我的 index.php 文件中有一个包含 indexTest.php 的测试文件夹的情况下使用 PHPUnit?
fat-free 指南给出了模拟路由请求和 POSTS 的代码片段。如果我直接在我的测试文件中生成具有任何功能的路由,我只能设法让这样的测试工作。
我想用令牌模拟一条路线,允许它从 index.php 中的路线 运行 并通过控制器并测试应由 [=23 设置的 f3 变量=]路线。
<?php
class indexTest extends \PHPUnit_Framework_TestCase
{
public function test()
{
$f3 = Base::instance();
// Don't write to STDOUT
$f3->set('QUIET', true);
$f3->route('GET /path', function(){ echo 'TEXT'; });
$this->assertNull($f3->mock('GET /path'));
$this->assertSame('TEXT', $f3->get('RESPONSE'));
$f3->route('GET /verify/@answer/@value',
function($f3, $params){
$errors = array();
$answer = $params['answer'];
$value = $params['value'];
$prefix = substr($answer, 0, 3); //pre, ans, pos
$id = (int)substr($answer, 3); //question id number (1, 2, 3, 4)
//$value is the input value from user
$result = check_id($prefix, $id, $value);
if($result !== true){
$errors[] = $result;
}
$f3->set('errors', $errors);
return $errors;
});
function check_id($prefix, $id, $value)
{
if($prefix == 'pre' || $prefix == 'pos'){
if($value <= 0 || $value > 180 || $value === NULL){
echo 'The input value of ' . $prefix . $id . ' question was out of bounds';
return 'The input value of ' . $prefix . $id . ' question was out of bounds';
}else{
return true;
}
}else if($prefix == 'ans'){
if($value < 0 || $value > 10 || $value === NULL){
echo 'The value of quiz ans' + $id + ' was out of bounds';
return 'The value of quiz ans' + $id + ' was out of bounds';
}else{
return true;
}
}else {
return 'The prefix does not match';
}
}
$this->assertNotNull($f3->mock('GET /verify/ans1/8'));
$this->assertEmpty($f3->get('RESPONSE')[0]);
$this->assertNotNull($f3->mock('GET /verify/dsk4/6'));
$this->assertSame('6', $f3->get('PARAMS.value'));
$this->assertSame('dsk4', $f3->get('PARAMS.answer'));
$this->assertEmpty($f3->get('RESPONSE')[0]);
$this->assertNotNull($f3->mock('GET /verify/pre4/250'));
$this->assertSame('The input value of pre4 question was out of bounds', $f3->get('errors')[0]);
$this->assertNotSame('pre4', $f3->get('PARAMS.answer'));
$f3->set('QUIET',FALSE); // allow test results to be shown later
$f3->clear('ERROR'); // clear any errors
}
}
我不想像这样声明整条路线,也许我完全错了,这是不可能的?上面的代码有效 运行ning vendor/bin/phpunit。在这方面很难找到相关的例子和教程。
简答
将您的控制器代码与 bootstrapping 和路由代码分开
在您的环境中重复使用路由配置,例如网站、CLI 和测试环境
在你的测试中使用
Base->mock()
来模拟之前定义的路由不要在测试环境中执行
Base->run()
长答案
早就想写一篇测试F3路线的文章了,但由于时间不够,我就在这里提几点:
创建一个定义路由的可重用文件(例如
routes.php
文件或具有路由定义的INI
文件)加载运行测试代码之前的路由。这可以通过 PHPUnit 的自定义 bootstrap 文件轻松完成(
--bootstrap <FILE>
或使用 PHPUnit 配置中的相应指令)。编写 PHPUnit 测试
示例
以下示例改编自我的 GitHub Gist:
bootstrap-website.php
<?php
$f3 = Base::instance();
require 'bootstrap-shared.php';
// [Custom rules only for the website here]
require 'routes.php';
$f3->run();
bootstrap-test.php
<?php
$f3 = Base::instance();
require 'bootstrap-shared.php';
// [Custom rules only for testing environment here]
$f3->set('QUIET', true);
$f3->set('APP.TEST', true);
require 'routes.php';
routes.php
<?php
/**
* @var $f3 Base
*/
$f3->route('GET /path', function(){ echo 'TEXT'; });
ExampleTest.php
class ExampleTest extends PHPUnit_Framework_TestCase {
public function test() {
// Could also be provided by a custom base TestCase.
$f3 = Base::instance();
$this->assertNull($f3->mock('GET /path'));
$this->assertSame('TEXT', $f3->get('RESPONSE'));
}
}
一些注意事项:
bootstrap-test.php
是 PHPUnit 的自定义 bootstrapping 文件
bootstrap-website.php
是网站的 bootstrapping 文件bootstrap-shared.php
包含所有环境共享的信息。该文件可能包含路由信息。我在例子中分离了路由信息:routes.php
ExampleTest.php
是一个常规的 PHPUnit 测试$f3->set('QUIET', true);
片段应添加到自定义 bootstrap 文件中。引入一个变量表明应用程序处于测试模式 运行 也是一个好主意,例如$f3->set('APP.TEST', true)
F3 不会清除 tests/mocks 之间的变量。您可以在 运行 测试之前存储原始状态,然后在 PHPUnit 的
setUp()
方法中恢复状态它 也足以只收集应该可用于呈现的数据,而不是呈现页面。在这种情况下,在您的视图中使用引入的
APP.TEST
变量来跳过渲染
稍后回答更新的注释
ini_set('error_log','./phpunit/error.log')
$f3->set('ONERROR',function(){});