답변:
배우기 훨씬 쉬운 세 번째 "프레임 워크"가 있습니다. Simple Test 보다 훨씬 쉽습니다 . 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
?
단위 테스트에 사용할 수있는 프레임 워크는 두 가지입니다. 내가 선호하는 Simpletest 및 PHPUnit . PHPUnit의 홈페이지에서 테스트를 작성하고 실행하는 방법에 대한 튜토리얼을 읽어보세요. 아주 쉽고 잘 설명되어 있습니다.
이를 수용하도록 코딩 스타일을 변경하여 단위 테스트를보다 효과적으로 만들 수 있습니다.
Google Testing 블로그 , 특히 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는 파이썬에서 시작되었으며 코드 작동 방식에 대한 유용하고 실행 가능한 예제를 제공하는 데 좋습니다. 코드 자체가 테스트 케이스로 가득 차 있기 때문에 독점적으로 사용할 수는 없지만 좀 더 공식적인 tdd 라이브러리와 함께 유용하다는 것을 발견했습니다. 저는 phpunit을 사용합니다.
이 첫 번째 대답 은 멋지게 요약합니다 (unit vs doctest가 아닙니다).
코드 셉션 테스트는 일반적인 단위 테스트와 매우 비슷하지만 조롱과 스터 빙이 필요한 경우 훨씬 강력합니다.
다음은 샘플 컨트롤러 테스트입니다. 스텁이 얼마나 쉽게 작성되는지 확인하십시오. 메소드가 호출되었는지 얼마나 쉽게 확인할 수 있습니다.
<?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');
}
}
또한 다른 멋진 것들이 있습니다. 데이터베이스 상태, 파일 시스템 등을 테스트 할 수 있습니다.
여기에 다시 게시하기에는 너무 많지만 여기 에 phpt 사용에 대한 훌륭한 기사 가 있습니다. 그것은 종종 간과되는 phpt 와 관련된 여러 측면을 다루기 때문에 단순히 테스트를 작성하는 것 이상으로 PHP에 대한 지식을 확장하기 위해 읽을 가치가 있습니다. 다행히이 기사는 쓰기 테스트에 대해서도 설명합니다!
논의의 요점
이미 여기에 많은 정보가 있다는 것을 알고 있지만 여전히 Google 검색에 표시되므로 Chinook Test Suite 를 목록에 추가 하는 것이 좋습니다. 간단하고 작은 테스트 프레임 워크입니다.
이를 사용하여 클래스를 쉽게 테스트하고 모의 객체를 만들 수도 있습니다. 웹 브라우저를 통해 그리고 (아직은 아님) 콘솔을 통해 테스트를 실행합니다 . 브라우저에서 실행할 테스트 클래스 또는 테스트 방법을 지정할 수 있습니다. 또는 단순히 모든 테스트를 실행할 수 있습니다.
github 페이지의 스크린 샷 :
내가 좋아하는 것은 테스트를 주장하는 방식입니다. 이것은 소위 "유창한 주장"으로 이루어집니다. 예:
$this->Assert($datetime)->Should()->BeAfter($someDatetime);
모의 객체를 만드는 것도 쉽습니다 (유창한 구문으로).
$mock = new CFMock::Create(new DummyClass());
$mock->ACallTo('SomeMethod')->Returns('some value');
어쨌든 더 많은 정보는 코드 예제와 함께 github 페이지에서 찾을 수 있습니다.