itsource

유닛 테스트를 PHP로 작성하려면 어떻게 해야 하나요?

mycopycode 2022. 12. 4. 22:35
반응형

유닛 테스트를 PHP로 작성하려면 어떻게 해야 하나요?

그들이 얼마나 훌륭한지에 대해 여기저기서 읽었지만, 어떤 이유에선지 정확히 어떻게 테스트해야 하는지 알 수 없는 것 같아요.누군가 코드 예시와 테스트 방법을 게시할 수 있을까요?번거롭지 않다면:)

세 번째 "프레임워크"가 있습니다.이것은 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"

In a nutshell, we provide the parameter 간단히 말해서, 우리는 파라미터를 제공한다.$bar with value 가치 있게"Hello World" and we 그리고 우리는.var_dump() the response of the function call to 에 대한 함수 호출 응답foo().

To run this test, use: 이 테스트를 실행하려면 다음을 사용합니다.pear run-test path/to/foo.phpt

이를 위해서는 시스템에 PEAR를 정상적으로 설치해야 합니다.이는 대부분의 경우 매우 일반적입니다.인스톨이 필요한 경우는, 이용 가능한 최신 버전을 인스톨 하는 것을 추천합니다.셋업에 도움이 필요한 경우 언제든지 문의해 주십시오(OS 제공 등).

유닛 테스트에는 2개의 프레임워크를 사용할 수 있습니다.심플테스트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();

출력은 다음과 같습니다.

테스트: Test One이 실패했습니다./*** 이 테스트는 실패하도록 설계되어 있습니다.**/ (행: 149-152; 파일:/Users/kris/Desktop/Testable.php)테스트: Test Two 성공

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;   
}

이 파일을 ppdt(php-doctest 명령줄 실행자)를 통해 실행하면 1개의 테스트가 실행됩니다.Doctest는 < code >블록 안에 포함되어 있습니다.Doctest는 python에서 시작되었으며, 코드가 어떻게 동작해야 하는지에 대한 유용하고 실행 가능한 예를 제시하는데 적합합니다.코드 자체가 테스트 케이스로 엉망이 되기 때문에 독점적으로 사용할 수는 없지만, 보다 정식적인 tdd 라이브러리와 함께 사용할 수 있다는 것을 알게 되었습니다.- 저는 phpunit을 사용하고 있습니다.

이 첫 번째 답변은 잘 요약되어 있습니다(유닛 vs doctest가 아닙니다.

phpunit은 거의 php의 defacto 유닛 테스트 프레임워크입니다.또한 DocTest(PEAR 패키지로 이용 가능)와 기타 몇 가지가 있습니다.php 자체는 phpt 테스트를 통해 회귀 등의 테스트를 수행하며 pear를 통해 실행할 수도 있습니다.

코드셉션 테스트는 일반적인 유닛테스트와 비슷하지만 조롱과 스텁이 필요한 경우 매우 강력합니다.

다음은 컨트롤러 테스트 예시입니다.스터브가 얼마나 쉽게 작성되는지 주목해 주세요.메서드가 얼마나 쉽게 호출되었는지 확인합니다.

<?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');
}
}

또한 다른 멋진 것들도 있습니다.데이터베이스 상태, 파일 시스템 등을 테스트할 수 있습니다.

이미 주어진 테스트 프레임워크에 대한 훌륭한 제안 외에, Symfony CakePHP와 같은 자동화된 테스트가 내장된 PHP 웹 프레임워크 중 하나로 애플리케이션을 구축하고 있습니까?경우에 따라서는 테스트 방법을 바로 사용할 수 있는 장소가 있으면 자동 테스트 및 TDD와 관련된 시동 마찰이 줄어들 수 있습니다.

여기에 다시 게시하기에는 너무 많은데, 여기 phpt 사용에 대한 훌륭한 기사가 있습니다.phpt에 관한 많은 측면을 망라하고 있기 때문에 php에 대한 지식을 단순히 테스트 작성에 그치지 않고 넓힐 수 있습니다.다행히 기사에서는 쓰기 테스트도 다루고 있습니다!

논의의 요점

  1. PHP의 극히 일부 문서화된 측면(또는 그 문제에 대한 거의 모든 부분)이 어떻게 작동하는지 확인하세요.
  2. 사용자 고유의 PHP 코드에 대한 간단한 장치 테스트 작성
  3. 확장의 일부로서 또는 내부 또는 QA 그룹에 잠재적인 버그를 전달하기 위해서 테스트를 작성합니다.

여기에 이미 많은 정보가 있다는 것을 알지만, 구글 검색에는 여전히 이 정보가 표시되므로 Chinook Test Suite를 목록에 추가하는 것이 좋습니다.이것은 간단하고 작은 테스트 프레임워크입니다.

당신은 이것으로 당신의 수업을 쉽게 테스트할 수 있고 또한 모의 객체를 만들 수 있습니다.테스트는 웹 브라우저를 통해(아직은) 콘솔을 통해 실행합니다.브라우저에서 실행할 테스트 클래스 또는 테스트 방법까지 지정할 수 있습니다.또는 단순히 모든 테스트를 실행할 수도 있습니다.

github 페이지의 스크린샷:

치누크 유닛 테스트 프레임워크

내가 좋아하는 건 네가 시험을 주장하는 방식이야.이것은 이른바 "유창한 주장"으로 이루어집니다.예:

$this->Assert($datetime)->Should()->BeAfter($someDatetime);

모의 객체 작성도 간단합니다(유창한 구문 사용).

$mock = new CFMock::Create(new DummyClass());
$mock->ACallTo('SomeMethod')->Returns('some value');

자세한 내용은 코드 예시와 함께 github 페이지에서 확인할 수 있습니다.

https://github.com/w00/Chinook-TestSuite

언급URL : https://stackoverflow.com/questions/282150/how-do-i-write-unit-tests-in-php

반응형