Answers:
有第三个“框架”,到目前为止,它很容易学习-比简单测试更容易,它叫做phpt。
可以在这里找到入门手册:http : //qa.php.net/write-test.php
编辑:刚看到您对示例代码的要求。
假设您在名为lib.php的文件中具有以下功能:
<?php
function foo($bar)
{
return $bar;
}
?>
返回的参数非常简单明了。因此,让我们看一下此功能的测试,我们将测试文件称为foo.phpt:
--TEST--
foo() function - A basic test to see if it works. :)
--FILE--
<?php
include 'lib.php'; // might need to adjust path if not in the same dir
$bar = 'Hello World';
var_dump(foo($bar));
?>
--EXPECT--
string(11) "Hello World"
简而言之,我们为参数$bar
提供value,"Hello World"
并且var_dump()
函数对的响应foo()
。
要运行此测试,请使用: pear run-test path/to/foo.phpt
这需要在系统上正常安装PEAR,这在大多数情况下是很常见的。如果您需要安装它,我建议安装可用的最新版本。如果您需要帮助进行设置,请随时询问(但提供操作系统等)。
run-tests
吗?
您可以使用两个框架进行单元测试。Simpletest和PHPUnit,我更喜欢。在PHPUnit主页上阅读有关如何编写和运行测试的教程。这很容易并且描述得很好。
您可以通过更改编码样式来适应它,从而使单元测试更加有效。
我建议浏览Google测试博客,尤其是有关编写可测试代码的文章。
我自己动手做,因为我没有时间去学习别人的做事方式,这花了大约20分钟来写,花了10分钟使它适合在这里发布。
单元测试对我来说非常有用。
这有点长,但是它说明了自己,并且在底部有一个示例。
/**
* Provides Assertions
**/
class Assert
{
public static function AreEqual( $a, $b )
{
if ( $a != $b )
{
throw new Exception( 'Subjects are not equal.' );
}
}
}
/**
* Provides a loggable entity with information on a test and how it executed
**/
class TestResult
{
protected $_testableInstance = null;
protected $_isSuccess = false;
public function getSuccess()
{
return $this->_isSuccess;
}
protected $_output = '';
public function getOutput()
{
return $_output;
}
public function setOutput( $value )
{
$_output = $value;
}
protected $_test = null;
public function getTest()
{
return $this->_test;
}
public function getName()
{
return $this->_test->getName();
}
public function getComment()
{
return $this->ParseComment( $this->_test->getDocComment() );
}
private function ParseComment( $comment )
{
$lines = explode( "\n", $comment );
for( $i = 0; $i < count( $lines ); $i ++ )
{
$lines[$i] = trim( $lines[ $i ] );
}
return implode( "\n", $lines );
}
protected $_exception = null;
public function getException()
{
return $this->_exception;
}
static public function CreateFailure( Testable $object, ReflectionMethod $test, Exception $exception )
{
$result = new self();
$result->_isSuccess = false;
$result->testableInstance = $object;
$result->_test = $test;
$result->_exception = $exception;
return $result;
}
static public function CreateSuccess( Testable $object, ReflectionMethod $test )
{
$result = new self();
$result->_isSuccess = true;
$result->testableInstance = $object;
$result->_test = $test;
return $result;
}
}
/**
* Provides a base class to derive tests from
**/
abstract class Testable
{
protected $test_log = array();
/**
* Logs the result of a test. keeps track of results for later inspection, Overridable to log elsewhere.
**/
protected function Log( TestResult $result )
{
$this->test_log[] = $result;
printf( "Test: %s was a %s %s\n"
,$result->getName()
,$result->getSuccess() ? 'success' : 'failure'
,$result->getSuccess() ? '' : sprintf( "\n%s (lines:%d-%d; file:%s)"
,$result->getComment()
,$result->getTest()->getStartLine()
,$result->getTest()->getEndLine()
,$result->getTest()->getFileName()
)
);
}
final public function RunTests()
{
$class = new ReflectionClass( $this );
foreach( $class->GetMethods() as $method )
{
$methodname = $method->getName();
if ( strlen( $methodname ) > 4 && substr( $methodname, 0, 4 ) == 'Test' )
{
ob_start();
try
{
$this->$methodname();
$result = TestResult::CreateSuccess( $this, $method );
}
catch( Exception $ex )
{
$result = TestResult::CreateFailure( $this, $method, $ex );
}
$output = ob_get_clean();
$result->setOutput( $output );
$this->Log( $result );
}
}
}
}
/**
* a simple Test suite with two tests
**/
class MyTest extends Testable
{
/**
* This test is designed to fail
**/
public function TestOne()
{
Assert::AreEqual( 1, 2 );
}
/**
* This test is designed to succeed
**/
public function TestTwo()
{
Assert::AreEqual( 1, 1 );
}
}
// this is how to use it.
$test = new MyTest();
$test->RunTests();
输出:
测试:TestOne失败 / ** *此测试旨在失败 ** /(行数:149-152;文件:/Users/kris/Desktop/Testable.php) 测试:TestTwo成功
获取PHPUnit。这是非常容易使用。
然后从非常简单的断言开始。在进行任何其他操作之前,您可以对AssertEquals进行很多操作。那是弄湿你的脚的好方法。
您可能还想先尝试编写测试(因为您给了问题TDD标签),然后编写代码。如果您还没做过,那就大开眼界。
require_once 'ClassYouWantToTest';
require_once 'PHPUnit...blah,blah,whatever';
class ClassYouWantToTest extends PHPUnit...blah,blah,whatever
{
private $ClassYouWantToTest;
protected function setUp ()
{
parent::setUp();
$this->ClassYouWantToTest = new ClassYouWantToTest(/* parameters */);
}
protected function tearDown ()
{
$this->ClassYouWantToTest = null;
parent::tearDown();
}
public function __construct ()
{
// not really needed
}
/**
* Tests ClassYouWantToTest->methodFoo()
*/
public function testMethodFoo ()
{
$this->assertEquals(
$this->ClassYouWantToTest->methodFoo('putValueOfParamHere), 'expectedOutputHere);
/**
* Tests ClassYouWantToTest->methodBar()
*/
public function testMethodFoo ()
{
$this->assertEquals(
$this->ClassYouWantToTest->methodBar('putValueOfParamHere), 'expectedOutputHere);
}
对于简单的测试和文档,php-doctest相当不错,这是一种非常容易上手的方法,因为您不必打开单独的文件。想象一下下面的函数:
/**
* Sums 2 numbers
* <code>
* //doctest: add
* echo add(5,2);
* //expects:
* 7
* </code>
*/
function add($a,$b){
return $a + $b;
}
如果现在通过phpdt(php-doctest的命令行运行程序)运行此文件,则将运行1个测试。doctest包含在<code>块中。Doctest起源于python,非常适合提供有用且可运行的示例,说明代码应如何工作。您不能专门使用它,因为代码本身会随测试用例而乱扔,但我发现它与更正式的tdd库一起使用非常有用-我使用phpunit。
这第一次的答案在这里概括起来很好(这不是单元VS文档测试)。
代码接收测试与普通的单元测试非常相似,但是在需要模拟和存根的功能上非常强大。
这是样品控制器测试。注意存根的创建是多么容易。您检查该方法被调用的难易程度。
<?php
use Codeception\Util\Stub as Stub;
const VALID_USER_ID = 1;
const INVALID_USER_ID = 0;
class UserControllerCest {
public $class = 'UserController';
public function show(CodeGuy $I) {
// prepare environment
$I->haveFakeClass($controller = Stub::makeEmptyExcept($this->class, 'show'));
$I->haveFakeClass($db = Stub::make('DbConnector', array('find' => function($id) { return $id == VALID_USER_ID ? new User() : null ))); };
$I->setProperty($controller, 'db', $db);
$I->executeTestedMethodOn($controller, VALID_USER_ID)
->seeResultEquals(true)
->seeMethodInvoked($controller, 'render');
$I->expect('it will render 404 page for non existent user')
->executeTestedMethodOn($controller, INVALID_USER_ID)
->seeResultNotEquals(true)
->seeMethodInvoked($controller, 'render404','User not found')
->seeMethodNotInvoked($controller, 'render');
}
}
还有其他很酷的东西。您可以测试数据库状态,文件系统等。
我知道这里已经有很多信息,但是由于这仍然会显示在Google搜索中,因此我不妨将Chinook Test Suite添加到列表中。这是一个简单而小型的测试框架。
您可以使用它轻松测试类,还可以创建模拟对象。您可以通过Web浏览器而不是通过控制台运行测试。在浏览器中,您可以指定要运行的测试类甚至测试方法。或者,您可以简单地运行所有测试。
github页面的屏幕截图:
我喜欢它是您断言测试的方式。这是通过所谓的“流利断言”完成的。例:
$this->Assert($datetime)->Should()->BeAfter($someDatetime);
创建模拟对象也很容易(使用流利的语法):
$mock = new CFMock::Create(new DummyClass());
$mock->ACallTo('SomeMethod')->Returns('some value');
无论如何,更多信息也可以在github页面上找到,并带有代码示例: