2008-12-05 12 views
4

Я пытаюсь проверить класс, который управляет доступом к данным в базе данных (вы знаете, CRUD, по существу). Библиотека DB мы используем случается иметь API, в котором вы сначала получить объект таблицы с помощью вызова статического:Mock Objects в PHPUnit для эмуляции вызовов статического метода?

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

... Вы получаете идею.

Мы пытаемся протестировать этот метод, но издеваемся над материалом DataObject, чтобы (a) нам не нужно фактическое соединение db для теста, и (b) нам даже не нужно включать DB_DataObject lib для теста.

Однако в PHPUnit я не могу получить $ this-> getMock() для правильной настройки статического вызова. У меня есть ...

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

... но тест все еще говорит неизвестный метод «завод». Я знаю, что он создает объект, потому что прежде, чем он сказал, что он не может найти DB_DataObject. Теперь это возможно. Но нет никакого метода?

Что я действительно хочу сделать, так это иметь два макетных объекта, один для возвращаемого объекта таблицы. Таким образом, мне не только нужно указать, что фабрика является статическим вызовом, но также и возвращает какой-то определенный другой макет, который я уже настроил.

Я должен упомянуть в качестве предостережения, что я сделал это в SimpleTest некоторое время назад (не могу найти код), и он отлично работал.

Что дает?

[UPDATE]

Я начинаю, чтобы понять, что у него есть что-то делать с предпологает()

ответ

2

Я согласен с вами обоими, что было бы лучше не использовать статический вызов. Однако, я думаю, я забыл упомянуть, что DB_DataObject является сторонней библиотекой, а статический вызов их - лучшая практика для их использования кода, а не для нас. Существуют и другие способы использования своих объектов, которые связаны с непосредственным конструированием возвращаемого объекта. Он просто оставляет эти проклятые include/require заявления в любом файле класса, использующем этот класс DB_DO. Это отстой, потому что тесты сломаются (или просто не будут изолированы), если вы тем временем пытаетесь высмеять класс с тем же именем в своем тесте - по крайней мере, я думаю.

1

Это хороший пример зависимости в вашем коде - дизайн сделал невозможным, чтобы придать в маке, а не в реальном классе.

Моим первым предложением было бы попробовать и реорганизовать код, чтобы использовать экземпляр вместо статического вызова.

0

Что не хватает (или нет?) Из вашего класса DB_DataObject, является установщиком для передачи подготовленного объекта db перед вызовом фабричного метода. Таким образом, вы можете передать макет или пользовательский объект db (с тем же интерфейсом), если возникнет такая необходимость.

В вашей тестовой конфигурации:

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

Фабричный метод() должен возвращать высмеивал экземпляр DB. Если он еще не интегрирован в ваш класс, вам, вероятно, придется реорганизовать метод factory(), чтобы он работал.

0

Вам нужен/включая файл класса для DB_DataObject в тестовом примере?Если класс не существует до того, как PHPUnit попытается высмеять объект, вы можете получить такие ошибки.

2

Если вы не можете изменить библиотеку, измените ее доступ к ней. Рефакторинг всех вызовов DB_DataObject :: завод() для метода экземпляра в коде:

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... 
} 
0

С расширением PHPUnit MockFunction плюс runkit вы также можете имитировать статические методы. Будьте осторожны, потому что это исправление обезьяны и поэтому должно использоваться только в крайних случаях. Не заменяет хорошую практику программирования.

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

 Смежные вопросы

  • Нет связанных вопросов^_^