문제

데이터베이스에서 데이터 액세스를 관리하는 클래스를 테스트하려고합니다 (본질적으로 CRUD). 우리가 사용하고있는 DB 라이브러리에는 API가 있는데, 여기서 먼저 정적 호출로 테이블 객체를 얻습니다.

function getFoo($id) {
  $MyTableRepresentation = DB_DataObject::factory("mytable");
  $MyTableRepresentation->get($id);
  ... do some stuff
  return $somedata
}

... 당신은 아이디어를 얻습니다.

우리는이 방법을 테스트하려고하지만 (a) 테스트를 위해 실제 DB 연결이 필요하지 않도록 데이터 객체 항목을 조롱하고 (b) 테스트를 위해 DB_DATAOBJECT LIB를 포함 할 필요조차 없습니다. .

그러나 PhPunit에서는 정적 호출을 적절하게 설정하기 위해 $ this-> getMock ()를 얻을 수없는 것 같습니다. 나는 가지고있다...

        $DB_DataObject = $this->getMock('DB_DataObject', array('factory'));

... 그러나 테스트는 여전히 알려지지 않은 방법 "공장"이라고 말합니다. DB_DataObject를 찾을 수 없기 때문에 객체를 만들고 있다는 것을 알고 있습니다. 이제 가능합니다. 그러나 방법이 없습니까?

내가 정말로하고 싶은 것은 두 개의 모의 개체를 갖는 것입니다. 하나는 테이블 객체를위한 것입니다. 따라서 공장이 정적 호출임을 지정해야 할뿐만 아니라 이미 설정 한 다른 Mock 객체를 반환해야합니다.

나는 얼마 전에 단순하게 이것을했다고 경고로 언급해야하며 (코드를 찾을 수 없음) 잘 작동했습니다.

무엇을 제공합니까?

업데이트

나는 그것이 exposts ()와 관련이 있다는 것을 이해하기 시작했습니다.

도움이 되었습니까?

해결책

나는 정적 호출을 사용하지 않는 것이 더 낫다는 것에 동의합니다. 그러나 DB_DataObject가 타사 라이브러리이고 정적 호출은 그들의 우리가 아닌 코드 사용에 대한 모범 사례. 반환 된 객체를 직접 구성하는 것과 관련된 객체를 사용하는 다른 방법이 있습니다. 그것은 단지 DB_DO 클래스를 사용하는 클래스 파일에 어떤 클래스 파일을 사용하는지 명령문을 포함시킵니다. 테스트에서 같은 이름의 클래스를 조롱하려고한다면 테스트가 깨지거나 격리되지 않기 때문에 짜증납니다.

다른 팁

라이브러리를 변경할 수 없으면 액세스를 변경하십시오. 코드의 인스턴스 메소드로 db_dataobject :: factory ()에 대한 모든 호출을 Refactor :

function getFoo($id) {
  $MyTableRepresentation = $this->getTable("mytable");
  $MyTableRepresentation->get($id);
  ... do some stuff
  return $somedata
}

function getTable($table) {
  return DB_DataObject::factory($table);
}

이제 테스트중인 클래스의 부분 모의를 사용할 수 있으며 GetTable ()가 모의 테이블 개체를 반환 할 수 있습니다.

function testMyTable() {
  $dao = $this->getMock('MyTableDao', array('getMock'));
  $table = $this->getMock('DB_DataObject', ...);
  $dao->expects($this->any())
      ->method('getTable')
      ->with('mytable')
      ->will($this->returnValue($table));
  $table->expects...
  ...test...
}

이것은 코드의 종속성의 좋은 예입니다. 디자인으로 인해 실제 클래스가 아닌 모의를 주입하는 것은 불가능했습니다.

첫 번째 제안은 정적 호출이 아닌 인스턴스를 사용하도록 코드를 리팩터링하는 것입니다.

DB_DataObject 클래스에서 누락 된 것은 공장 메소드를 호출하기 전에 준비된 DB 객체를 전달하는 세터입니다. 이렇게하면 필요가 발생하면 모의 또는 맞춤형 DB 객체 (동일한 인터페이스 포함)를 전달할 수 있습니다.

테스트 설정에서 :

 public function setUp() {
      $mockDb = new MockDb();
      DB_DataObject::setAdapter($mockDb);
 }

Factory () 메소드는 조롱 된 DB 인스턴스를 반환해야합니다. 아직 수업에 통합되지 않은 경우 공장 () 메소드를 리팩터링하고 작동하도록해야 할 것입니다.

테스트 케이스에서 DB_DATAOBJECT의 클래스 파일을 포함시켜야합니까? PHPUNIT가 개체를 조롱하려고 시도하기 전에 클래스가 존재하지 않으면 이와 같은 오류를 얻을 수 있습니다.

phpunit mockfunction extension plus runkit을 사용하면 정적 메소드를 조롱 할 수도 있습니다. 원숭이 패치이기 때문에 조심해야하므로 극한의 경우에만 사용해야합니다. 좋은 프로그래밍 관행을 대체하지 않습니다.

https://github.com/tcz/phpunit-mockfunction

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