回答:
3番目の「フレームワーク」があります。これは、はるかに簡単に学習できます。シンプルよりもさらに簡単です。テスト、それが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
に値"Hello World"
を指定しvar_dump()
、関数呼び出しの応答をfoo()
。
このテストを実行するには、次を使用します。 pear run-test path/to/foo.phpt
これには、システムにPEARをインストールする必要があります。これは、ほとんどの状況でかなり一般的です。インストールする必要がある場合は、入手可能な最新バージョンをインストールすることをお勧めします。設定の手助けが必要な場合は、遠慮なく尋ねてください(ただし、OSなどを提供してください)。
run-tests
?
単体テストに使用できるフレームワークは2つあります。SimpletestとPHPUnitです。PHPUnitのホームページでテストを作成して実行する方法に関するチュートリアルを読んでください。とても簡単で、よく説明されています。
コーディングスタイルを変更してそれに対応することで、ユニットテストをより効果的にすることができます。
Google Testing Blog、特にWriting Testable Codeに関する投稿を閲覧することをお勧めします。
他の人のやり方を学ぶ時間がなかったので、自分で転がしました。これを書くのに約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を使用しています。
この最初の答えは、ここでうまくまとめられています(ユニット対doctestではありません)。
Codeceptionテストは一般的な単体テストによく似ていますが、モックやスタブが必要な場合には非常に強力です。
これは、コントローラーのサンプルテストです。スタブがいかに簡単に作成されるかに注意してください。メソッドが呼び出されたことを簡単に確認できます。
<?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ページでコード例とともに見つかります: