phpUnit моки для несуществующих классов и методов

AmdY

Пью пиво
Команда форума
Пытаюсь начать разрабатывать с использованием phpUnit. Раньше использовал метод, когда сразу пишу цепочки вызовов, а код самих классов дописываю потом.
PHP:
$url = new Url('controller', 'action');
$url->setController('controller');
$url->setAction('action');
$url->set('page', 10);
echo $url; //   controller/action/page:10/
Сейчас делаю точно так же, только сразу пишу тесты с ассертами, а затем пытаюсь их пройти, дописывая код методов по мере надобности. Здесь здорово помогают Mock, но не получается создать для несуществующих классов и методов.
PHP:
<?php

class Foo {

	public function getItem($id) {
		
	}

}

class Kiss_MockTest extends PHPUnit_Framework_TestCase {

	public function testOne() {
		$class = $this->getMock('Foo');
		$class->expects($this->any())
				->method('getItem')
				->will($this->returnCallback(array($this, 'callbackGetItem')));
		$this->assertEquals(1, $class->getItem(1));
		$this->assertEquals(2, $class->getItem(2));
		$this->assertEquals(1, $class->getItem(1));
	}

	public function testTwo() {
		$class = $this->getMock('Foo');
		$class->expects($this->any())
				->method('notExistsMethod')
				->will($this->returnCallback(array($this, 'callbackGetItem')));
		$this->assertEquals(1, $class->notExistsMethod(1));
	}

	public function callbackGetItem($value) {
		switch ($value) {
			case 1:
				return 1;
				break;
			case 2:
				return 2;
				break;
		}
	}
}
?>
Тест тестирующий ещё не написанный notExistsMethod не работает

Fatal error: Call to undefined method Mock_Foo_5fe30c3b::notExistsMethod() in MockTest.php on line 28
 

whirlwind

TDD infected, paranoid
whirlwind
спасибо, помогло.
Хошь совет? Тут ты идешь по тонкому льду. Если такая работа с моками войдет в привычку, жди беды.

1. явное - что бы понять, что происходит, нужно будет скакать в колбек метод.
2. скрытое - такие моки нечуствительны к изменениям.

Вместо мока на класс делай мок на интерфейс. Это не решит всех проблем (просто специфика пыха), но какую то часть решит.
 

AmdY

Пью пиво
Команда форума
правильнее и прозрачнее будет перед каждым вызовом собирать мок или я смотрю не на ту проблему?
PHP:
        $class = $this->getMock('Foo');

        $class->expects($this->at(0))
                ->method('getItem')
                ->with($this->equalTo(1))               
                ->will($this->returnValue(1));
        $this->assertEquals(1, $class->getItem(1));

        $class->expects($this->at(1))
                ->method('getItem')
                ->with($this->equalTo(2))
                ->will($this->returnValue('two'));
        $this->assertEquals('two', $class->getItem(2));
 

whirlwind

TDD infected, paranoid
Да. При чем много кода сборки мока будет намекать на то, что есть лучший путь и пора сменить точку обзора :D
 

AmdY

Пью пиво
Команда форума
whirlwind
о, спасибо, хорошая статья о использовании моков в phpunit http://prolib.ru/mocks , нашёл у тебя в подписи.
 

whirlwind

TDD infected, paranoid
AmdY не, она сумбурная. Все никак руки не дойдут дописать.
 

fixxxer

К.О.
Партнер клуба
Вместо мока на класс делай мок на интерфейс.
о!

Получается, что когда надо писать мок, который не является скажем так "минимально разумной реализацией интерфейса", а на класс или его достаточно сложное поведение, что это значит, что у меня не api а говно. Ну как-то так оно и есть. :)
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Внезапно, с десятка этих сообщений я кажется поймал «соль» юнит-тестов. :) Пойду учить пробовать :)
 

atv

Новичок
Эээ, AmdY мне кажется ты слишком буквально понимаешь тезис "писать тесты до реализации". Точнее не совсем правильно понимаешь. Как минимум, интерфейс класса уже должен быть, а сама реализация после теста, как и отмечено в тезисе. Упомянутый тезис не означает, что ты должен на всю систему написать тесты и только потом делать реализацию. Делается небольшими порциями, по одному методу.

Ещё раз хочу подчеркнуть, юнит тесты идут перед реализацией, а не перед проектированием. На самом верхнем уровне идут функциональные тесты, которые и есть требования к системе. По этим требования проектируется система, т.е. выделяются сущности и связи между ними. А уже на них пишутся юнит тесты.
 

Mols

Новичок
Чего то я тоже не въехал как это "...Тест тестирующий ещё не написанный notExistsMethod не работает..." ?
Если этот метод заменяется в моке дык он вообще не тестируется(в тестах где используется такой мок).
Ни сейчас, ни после его реализации в классе.
Я имею в виду сам метод notExistsMethod
 

AmdY

Пью пиво
Команда форума
Mols
угу, в данном случае я разбирался как работают моки, поэтому тестировал их.

atv
я не пытаюсь следовать принципу, у меня есть свой подход, срузу пишу цепочки вызовов, чтобы представить апи, затем пытаюсь чтобы этот код заработал. для этого создаю по мере надобности классы и методы. 7-й нетбинс поддерживает генерацию кода, так что это весьма удобно.
 

Вложения

grigori

( ͡° ͜ʖ ͡°)
Команда форума
> 7-й нетбинс поддерживает генерацию кода
ух ты, а в нужном каталоге в соответствии с неймспейсом - не создаст? а то ж каждый раз переносить
 

fixxxer

К.О.
Партнер клуба
Как минимум, интерфейс класса уже должен быть, а сама реализация после теста, как и отмечено в тезисе.
Зависит от. Часто удобнее начать с теста, чем заранее проектировать в голове. По тесту намного понятнее каким должно быть API, и сразу вылезает то, о чем сразу мог не подумать.
 

zerkms

TDD infected
Команда форума
Зависит от. Часто удобнее начать с теста, чем заранее проектировать в голове. По тесту намного понятнее каким должно быть API, и сразу вылезает то, о чем сразу мог не подумать.
Зависит от направления разработки - снизу вверх или сверху вниз.

В первом случае такая ситуация невозможна по определению - потому что всё, что ты можешь и должен мокать уже создано.
А во втором случае да, реализация нижлежащих классов (и интерфейсы) могут вообще не существовать.
 
Сверху