2016-06-04 2 views
1

Создание макетных классов обычно включает в себя настройку ожиданий вызова метода на парные/тестовые пары.Метод ожидания метода PHPUnit против утверждений

E.g. в «ванильный» PHPUnit мы можем незавершенная вызов метода и установить ожидания, как так:

$stub->expects($this->any())->method('doSomething')->willReturn('foo');

В макете рамках объекта Mockery, мы получим API, как это:

$mock->shouldReceive('doIt')->with(m::anyOf('this','that'))->andReturn($this->getSomething());

Ожидания, подобные этим, часто связаны на этапе настройки тестового набора, например setUp() метод \PHPUnit_Framework_TestCase.

Ожидания, подобные приведенным выше, нарушат тест, если они не будут выполнены. Следовательно, ожидание является реальным утверждением.

Это приводит к ситуации, когда у нас есть утверждения (утверждения + ожидания), разбросанные по классу тестового случая, так как мы получаем фактические утверждения на этапе настройки тестового примера, а также в отдельных тестах.

Было бы хорошей практикой, чтобы проверить ожидаемые вызовы метода в 'regular' assert... Это может выглядеть, что (насмешка):

public function setUp() 
{ 
    $mock = m::mock(SomeClass::class); 
    $mock->shouldReceive('setSomeValue'); 
    $this->mock = $mock; 
} 

и затем в конце одного из методов испытаний:

public function testSoemthing() 
{ 
    ... 
    $this->assertMethodCalled($this->mock, 'setSomeValue'); 
} 

assertMethodCalled в не методом выставленного PHPUnit. Это должно быть реализовано.

Короче говоря, следует ли рассматривать заявления о ожидании как фактические утверждения и, следовательно, проверять их в наших методах тестирования?

ответ

2

Вам не нужно настраивать тестовые двойники (заглушки/макеты) в методе setUp().

На самом деле, я бы никогда не сконфигурировал макет в тестовом установочном коде, и я бы разместил там очень распространенные заглушки. Макетные ожидания очень часто различаются для каждого теста. Я бы предпочел создать экземпляр тестовых двойников в установочном коде, назначить их частным свойствам и настроить их в каждом тестовом случае.

private $registration; 
private $repository; 

protected function setUp() 
{ 
    $this->repository = $this->getMock(UserRepository::class); 
    $this->registration = new Registration($repository); 
} 

public function testUserIsAddedToTheRepositoryDuringRegistration() 
{ 
    $user = $this->createUser(); 

    $this->repository 
     ->expects($this->once()) 
     ->method('add') 
     ->with($user); 

    $this->registration->register($user); 
} 

Так что это нормально, чтобы поставить тестовую двойную конфигурацию в тестовом корпусе. Это на самом деле лучше, так как ваш тестовый пример имеет весь контекст и, следовательно, более читабельен. Если вы обнаружите, что настраиваете множество тестовых удвоений или записываете длинные тестовые примеры, это может означать, что у вас слишком много сотрудников, и вы должны подумать о том, как улучшить свой дизайн. Вы также можете использовать вспомогательные методы со значимыми именами, чтобы сделать ваши тестовые примеры более читаемыми - то есть $this->givenExistingUser() или $this->givenRepositoryWithNoUsers().

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

Шпионы не поддерживаются классическим фальшивым фальшивым фреймворком. Однако PHPUnit теперь имеет встроенную поддержку пророчества. К счастью, пророчество supports spies.Вот пример:

private $registration; 
private $repository; 

protected function setUp() 
{ 
    $this->repository = $this->prophesize(UserRepository::class); 
    $this->registration = new Registration($repository->reveal()); 
} 

public function testUserIsAddedToTheRepositoryDuringRegistration() 
{ 
    $user = $this->createUser(); 

    $this->registration->register($user); 

    $this->repository->add($user)->shouldHaveBeenCalled(); 
} 

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

Чтобы узнать больше о испытательных двухместных номерах, прочитайте превосходные PHP Test Doubles Patterns.

+0

Благодарим за ценный совет. Я также обнаружил, что MockInterface Mockery также предоставляет метод 'shouldHaveBeenCalled()', поэтому его можно использовать аналогично тому, что вы показали с Prophecy. Также будет намного лучше проверить ожидаемые вызовы метода отдельно от других действий. В заключение я думаю, что можно с уверенностью утверждать, что 'shouldHaveBeenCalled()' является полноправным утверждением и требует собственного тестового примера. – luqo33

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

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