2009-08-07 3 views
10

SimpleTest로 PHP 코드를 단위 테스트하고 문제가 생겼습니다. 데이터베이스 클래스에 대한 테스트에서 PHP mysql 함수에 대한 기대치를 설정할 수 있기를 원합니다. mail 함수에 대한 래퍼 클래스 테스트에서 PHP를 모의하고 싶습니다 mail 함수. 이것들은 단지 몇 가지 예입니다.단위 테스트에서 PHP 함수 조롱하기

요점은 다음과 같습니다. Mail 클래스가 전자 메일을 보내는 지 테스트하고 싶지는 않지만 mail 함수를 호출하는 방법을 테스트하고 싶습니다. 이 함수가 반환하는 것을 제어 할 수 있기를 원합니다. 데이터베이스, 비품 및 그 전체를 필요로하지 않고도 데이터베이스 클래스를 테스트 할 수 있기를 원합니다.

Ruby 코드를 테스트 한 경험이 있고 Test :: Unit 및 RSpec은 코드를 독립적으로 테스트하는 것을 매우 쉽게 만듭니다. 나는 PHP를 처음 사용하는 것에 익숙하며, 필자는 테스트를 통과하기 위해 필자가해야 할 것보다 더 많은 것을 테스트하고있는 것처럼 느낀다.

SimpleTest 또는 PhpUnit 또는 다른 테스트 프레임 워크에서이를 가능하게하거나 더 쉽게 만들 수있는 방법이 있습니까?

답변

10

자동화 된 방식이 아닙니다. 할 수있는 일은 외부 종속성이 외부에서 전달되는 객체에 래핑되는 방식으로 코드를 작성하는 것입니다. 프로덕션 환경에서는 실제 어댑터를 연결 만하면되지만 테스트 중에는 스텁이나 모의 객체에 연결할 수 있습니다.

정말로 고집한다면, runkit extension을 사용하면 PHP의 프로그래밍 모델을 변경할 수 있으므로 런타임에 클래스와 함수를 다시 정의 할 수 있습니다. 그러나 외부 및 비표준 확장 기능이므로이를 염두에 두시기 바랍니다. defacto 표준은 위에서 설명한 수동 접근 방식입니다.

+0

나는보고 있습니다. 나는 그런 종류의 대답을 기대한다 (그러나 기대하지는 않는다). 나는 테스트를 단순화하고 속도를 높이고 더 복잡하게 만들지 않기 때문에 정말로 주장하지 않습니다. 귀하의 회신에 감사드립니다! – avdgaag

+0

이제 [조롱] (http://docs.mockery.io/en/latest/cookbook/mocking_hard_dependencies.html)이 [떠날 방법 인 것 같습니다] (http://stackoverflow.com/a/42158443/659788). – Franco

+1

@Franco 기본 제공되지 않습니다. – troelskn

0

는 PHP 5.3+ 환경에서는 네임 스페이스를 해킹 runkit 확장을 사용할 필요를 해결 할 수 있습니다. 함수 호출이 \mysql_query()과 같이 정규화 된 네임 스페이스를 사용하지 않는다는 유일한 요구 사항은 일반적으로 필요하지 않습니다. 그런 다음 네임 스페이스에서 테스트를 정의하여 테스트에서 동일한 함수를 정의 할 수 있으며 PHP는 전역 함수 대신 함수를 호출합니다. 개인적으로이 방법을 사용하여 time() 함수 호출을 스텁 (stub) 처리합니다. 다음은 nice example with the mockery framework

+0

[php-mock] (https : // github.com/php-mock/php-mock)을 사용하여 그러한 모의 객체를 만듭니다. –

1

Here is an interesting article이며 글로벌 PHP 함수를 조롱합니다. 저자는 SUT의 네임 스페이스 안에있는 메소드를 덮어 쓰는 것으로 글로벌 php 함수를 '모의 (Mock)'(kind off)하는 매우 창의적인 솔루션을 제안합니다. time 기능을 조롱하는 블로그 게시물의 예에서 다음

코드 :이 그것을 할 수있는 좋은 방법이지만 반드시 잘 작동하고 나는 그것을 언급 할 가치가있다 생각하는 경우

<?php 

namespace My\Namespace; 

use PHPUnit_Framework_TestCase; 

/** 
* Override time() in current namespace for testing 
* 
* @return int 
*/ 
function time() 
{ 
    return SomeClassTest::$now ?: \time(); 
} 

class SomeClassTest extends PHPUnit_Framework_TestCase 
{ 
    /** 
    * @var int $now Timestamp that will be returned by time() 
    */ 
    public static $now; 

    /** 
    * @var SomeClass $someClass Test subject 
    */ 
    private $someClass; 

    /** 
    * Create test subject before test 
    */ 
    protected function setUp() 
    { 
     parent::setUp(); 
     $this->someClass = new SomeClass; 
    } 

    /** 
    * Reset custom time after test 
    */ 
    protected function tearDown() 
    { 
     self::$now = null; 
    } 

    /* 
    * Test cases 
    */ 
    public function testOneHourAgoFromNoon() 
    { 
     self::$now = strtotime('12:00'); 
     $this->assertEquals('11:00', $this->someClass->oneHourAgo()); 
    } 
    public function testOneHourAgoFromMidnight() 
    { 
     self::$now = strtotime('0:00'); 
     $this->assertEquals('23:00', $this->someClass->oneHourAgo()); 
    } 
} 

확실하지 않음 이리. 토론을위한 음식이 될 수 있습니다 ...