문제

나는 논의를 발견했다 개인 방법을 테스트합니까? 유익한.

나는 일부 수업에서는 보호 방법을 원하지만 테스트하기로 결정했습니다. 이러한 방법 중 일부는 정적이고 짧습니다. 대부분의 공개 방법이이를 사용하기 때문에 나중에 테스트를 안전하게 제거 할 수있을 것입니다. 그러나 TDD 접근 방식으로 시작하여 디버깅을 피하기 위해 실제로 테스트하고 싶습니다.

나는 다음을 생각했다.

  • 메소드 객체 유언 된대로 답변 이것에 대한 과잉 인 것 같습니다.
  • 공개 방법으로 시작하고 더 높은 수준의 테스트로 코드 커버리지가 제공되면 보호를 받고 테스트를 제거하십시오.
  • 보호 된 방법 공개를 만드는 테스트 가능한 인터페이스로 클래스 상속

모범 사례는 무엇입니까? 다른 것이 있습니까?

Junit은 보호 된 방법을 자동으로 공개적으로 변경하는 것으로 보이지만 더 깊이 살펴 보지 않았습니다. PHP는 이것을 통해 허용하지 않습니다 반사.

도움이 되었습니까?

해결책

PHPUnit과 함께 PHP5 (> = 5.3.2)를 사용하는 경우 테스트를 실행하기 전에 반사를 사용하여 공개되도록 설정하여 개인 및 보호 방법을 테스트 할 수 있습니다.

protected static function getMethod($name) {
  $class = new ReflectionClass('MyClass');
  $method = $class->getMethod($name);
  $method->setAccessible(true);
  return $method;
}

public function testFoo() {
  $foo = self::getMethod('foo');
  $obj = new MyClass();
  $foo->invokeArgs($obj, array(...));
  ...
}

다른 팁

당신은 이미 알고있는 것 같지만 어쨌든 그것을 다시 할 것입니다. 보호 된 방법을 테스트 해야하는 경우 나쁜 신호입니다. 단위 테스트의 목표는 클래스의 인터페이스를 테스트하는 것이며 보호 된 방법은 구현 세부 사항입니다. 즉, 의미가있는 경우가 있습니다. 상속을 사용하는 경우 슈퍼 클래스가 서브 클래스의 인터페이스를 제공하는 것으로 볼 수 있습니다. 그래서 여기서, 당신은 보호 된 방법을 테스트해야 할 것입니다 (그러나 결코 사적인 하나). 이에 대한 해결책은 테스트 목적을위한 서브 클래스를 만들고이를 사용하여 방법을 노출시키는 것입니다. 예를 들어 :

class Foo {
  protected function stuff() {
    // secret stuff, you want to test
  }
}

class SubFoo extends Foo {
  public function exposedStuff() {
    return $this->stuff();
  }
}

항상 상속을 구성으로 대체 할 수 있습니다. 코드를 테스트 할 때는 일반적 으로이 패턴을 사용하는 코드를 처리하는 것이 훨씬 쉽기 때문에 해당 옵션을 고려할 수 있습니다.

티스트번 올바른 접근 방식이 있습니다. 더 간단하게 메소드를 호출하고 답을 반환하는 것입니다.

class PHPUnitUtil
{
  public static function callMethod($obj, $name, array $args) {
        $class = new \ReflectionClass($obj);
        $method = $class->getMethod($name);
        $method->setAccessible(true);
        return $method->invokeArgs($obj, $args);
    }
}

테스트에서 간단히 호출 할 수 있습니다.

$returnVal = PHPUnitUtil::callMethod(
                $this->object,
                '_nameOfProtectedMethod', 
                array($arg1, $arg2)
             );

정의 된 getMethod ()에 약간의 변형을 제안하고 싶습니다. Uckelman의 대답.

이 버전은 하드 코딩 된 값을 제거하고 사용법을 단순화하여 getMethod ()를 변경합니다. 아래 예제와 같이 PhpUnitutil 클래스 또는 phpUnit_framework_testcase-extending 클래스에 추가하는 것이 좋습니다 (또는 전 세계적으로 phpunitutil 파일에 대해 생각합니다).

MyClass가 어쨌든 인스턴스화되고 있으므로 반사 클래스는 문자열이나 객체를 가져갈 수 있습니다 ...

class PHPUnitUtil {
    /**
     * Get a private or protected method for testing/documentation purposes.
     * How to use for MyClass->foo():
     *      $cls = new MyClass();
     *      $foo = PHPUnitUtil::getPrivateMethod($cls, 'foo');
     *      $foo->invoke($cls, $...);
     * @param object $obj The instantiated instance of your class
     * @param string $name The name of your private/protected method
     * @return ReflectionMethod The method you asked for
     */
    public static function getPrivateMethod($obj, $name) {
      $class = new ReflectionClass($obj);
      $method = $class->getMethod($name);
      $method->setAccessible(true);
      return $method;
    }
    // ... some other functions
}

또한 예상되는 것을 명시 적으로 만들기 위해 별칭 함수 getProtectedMethod ()를 만들었지 만 그 사람은 당신에게 달려 있습니다.

건배!

나는 Troelskn이 가까이 있다고 생각합니다. 대신 이것을 할 것입니다.

class ClassToTest
{
   protected testThisMethod()
   {
     // Implement stuff here
   }
}

그런 다음 다음과 같은 것을 구현하십시오.

class TestClassToTest extends ClassToTest
{
  public testThisMethod()
  {
    return parent::testThisMethod();
  }
}

그런 다음 TestClasstotest에 대해 테스트를 실행합니다.

코드를 구문 분석하여 이러한 확장 클래스를 자동으로 생성 할 수 있어야합니다. PHPUNIT가 이미 그러한 메커니즘을 제공한다고해도 놀라지 않을 것입니다 (확인하지는 않았지만).

나는 여기에 내 모자를 반지에 던질 것이다 :

나는 __call 해킹을 혼합 된 성공으로 사용했습니다. 내가 생각해 낸 대안은 방문자 패턴을 사용하는 것이 었습니다.

1 : STDCLASS 또는 사용자 정의 클래스를 생성합니다 (유형을 시행하기 위해)

2 : 필요한 방법과 인수로 프라임

3 : SUT가 방문 클래스에 지정된 인수와 함께 메소드를 실행하는 acceptvisitor 메소드가 있는지 확인

4 : 테스트하려는 클래스에 주입하십시오.

5 : SUT는 방문자에 작동 결과를 주입합니다.

6 : 방문자의 결과 속성에 테스트 조건을 적용하십시오.

실제로 __call ()를 일반적인 방식으로 사용하여 보호 된 방법에 액세스 할 수 있습니다. 이 수업을 테스트 할 수 있습니다

class Example {
    protected function getMessage() {
        return 'hello';
    }
}

emabletest.php에서 하위 클래스를 만듭니다.

class ExampleExposed extends Example {
    public function __call($method, array $args = array()) {
        if (!method_exists($this, $method))
            throw new BadMethodCallException("method '$method' does not exist");
        return call_user_func_array(array($this, $method), $args);
    }
}

__call () 메소드는 클래스를 어떤 식 으로든 참조하지 않으므로 테스트하려는 보호 된 방법으로 각 클래스에 대해 위를 복사하고 클래스 선언을 변경할 수 있습니다. 이 기능을 공통 기본 클래스에 배치 할 수는 있지만 시도하지 않았습니다.

이제 테스트 케이스 자체는 테스트 할 객체를 구성하는 위치에만 다릅니다.

class ExampleTest extends PHPUnit_Framework_TestCase {
    function testGetMessage() {
        $fixture = new ExampleExposed();
        self::assertEquals('hello', $fixture->getMessage());
    }
}

PHP 5.3을 사용하면 반사를 사용하여 메소드의 접근성을 직접 변경할 수 있지만 각 방법에 대해 개별적으로 그렇게해야한다고 가정합니다.

"Henrik Paul"의 해결 방법/아이디어에 대한 해결 방법 :)

당신은 당신의 수업의 개인 방법의 이름을 알고 있습니다. 예를 들어 _add (), _edit (), _delete () 등과 같습니다.

따라서 단위 테스트 측면에서 테스트하려는 경우 일부 접두사 및/또는 접미사를 통해 개인 메소드를 호출하십시오. 흔한 Word (예 : _addphPunit) __call () 메소드가 호출되면 (메소드 _addphPunit ()가 존재하지 않기 때문에)가 소유자 클래스의 클래스가 호출되면 __call () 메소드에 필요한 코드를 넣습니다. ) 그런 다음 거기에서 그 추론 된 개인 방법을 부릅니다. 이것은 마법 방법의 또 다른 사용입니다.

시도해보십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top