Тестовые дубликаты
Gerard Meszaros вводит концепцию тестовых дубликатов в Meszaros2007 так:
Gerard Meszaros:
Иногда просто сложно протестировать систему, на которой проводятся тесты (SUT), потому что она зависит от других компонентов, которые нельзя использовать в тестовой среде. Это может быть потому, что они недоступны, они не вернут необходимые результаты для теста или их выполнение повлияет нежелательным образом. В других случаях наша стратегия тестирования требует большего контроля или видимости внутреннего поведения SUT.
Когда мы пишем тест, в котором мы не можем (или не хотим) использовать реальный зависимый компонент (DOC), мы можем заменить его тестовым дубликатом. Тестовый дубликат не обязан вести себя точно так же, как реальный DOC; он просто должен предоставить тот же API, что и реальный, чтобы SUT думал, что это реальный!
Методы createStub($type), createMock($type), и getMockBuilder($type) предоставляемые PHPUnit, могут быть использованы в тесте для автоматического создания объекта, который может действовать как тестовый дубликат для указанного исходного типа (интерфейс или имя класса). Этот объект тестового дубликата может быть использован в любом контексте, где ожидается или требуется объект исходного типа.
Методы createStub($type) и createMock($type) немедленно возвращают объект тестового дубликата для указанного типа (интерфейс или класс). Создание этого тестового дубликата выполняется с использованием лучших практик по умолчанию. Методы __construct() и __clone() исходного класса не выполняются, а аргументы, переданные методу тестового дубликата, не будут клонированы. Если эти значения по умолчанию не подходят, вы можете использовать метод getMockBuilder($type) для настройки генерации тестового дубликата с использованием интерфейса fluent.
По умолчанию все методы исходного класса заменяются имитацией, которая возвращает null (без вызова исходного метода). Например, с помощью метода will($this->returnValue()) вы можете настроить эти имитации, чтобы они возвращали значение при вызове.
Ограничение: методы final, private и static
Обратите внимание, что методы final, private, и static не могут быть подставлены или смоделированы. Они игнорируются функциональностью тестовых дубликатов PHPUnit и сохраняют свое исходное поведение, за исключением методов static, которые будут заменены методом, выбрасывающим исключение \PHPUnit\Framework\MockObject\BadMethodCallException.
Заглушки
Практика замены объекта на тестовый дубликат, который (необязательно) возвращает настроенные возвращаемые значения, называется заглушкой. Вы можете использовать заглушку для «замены реального компонента, от которого зависит SUT, таким образом, чтобы тест имел точку управления для косвенных входных данных SUT. Это позволяет тесту заставить SUT пройти пути, которые он иначе мог бы не выполнить».
Пример 8.2 показывает, как подставить вызовы методов и настроить возвращаемые значения. Сначала мы используем метод createStub(), который предоставляется классом PHPUnit\Framework\TestCase, для настройки объекта заглушки, который выглядит как объект SomeClass (Пример 8.1). Затем мы используем Fluent Interface, который предоставляет PHPUnit, для указания поведения заглушки. По сути, это означает, что вам не нужно создавать несколько временных объектов и соединять их впоследствии. Вместо этого вы можете цеплять вызовы методов, как показано в примере. Это приводит к более читаемому и «плавному» коду.
<?php declare(strict_types=1);
class SomeClass
{
public function doSomething()
{
// Do something.
}
}
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willReturn('foo');
// Calling $stub->doSomething() will now return
// 'foo'.
$this->assertSame('foo', $stub->doSomething());
}
}
Ограничение: Методы с именем «method»
Приведенный выше пример работает только в том случае, если исходный класс не объявляет метод с именем «method».
Если исходный класс объявляет метод с именем «method», то необходимо использовать $stub->expects($this->any())->method('doSomething')->willReturn('foo');.
«За кулисами» PHPUnit автоматически генерирует новый класс PHP, который реализует желаемое поведение при использовании метода createStub().
Обратите внимание, что createStub() автоматически и рекурсивно заглушает возвращаемые значения на основе типа возврата метода. Рассмотрим пример ниже:
<?php declare(strict_types=1);
class C
{
public function m(): D
{
// Do something.
}
}
В приведенном выше примере метод C::m() имеет объявление типа возврата, указывающее, что этот метод возвращает объект типа D. При создании тестового дубликата для C и отсутствии настроенного возвращаемого значения для m() с помощью willReturn() (см. выше), например, при вызове m() PHPUnit автоматически создаст тестовый дубликат для D для возврата.
Аналогично, если m имел объявление типа возврата для скалярного типа, то возвращаемым значением будет, например, 0 (для int), 0.0 (для float) или [] (для array).
Пример 8.4 показывает пример использования fluent интерфейса Mock Builder для настройки создания тестового дубликата. Настройка этого тестового дубликата использует те же значения по умолчанию, что и createStub().
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->getMockBuilder(SomeClass::class)
->disableOriginalConstructor()
->disableOriginalClone()
->disableArgumentCloning()
->disallowMockingUnknownTypes()
->getMock();
// Configure the stub.
$stub->method('doSomething')
->willReturn('foo');
// Calling $stub->doSomething() will now return
// 'foo'.
$this->assertSame('foo', $stub->doSomething());
}
}
В предыдущих примерах мы возвращали простые значения с помощью willReturn($value). Этот короткий синтаксис эквивалентен will($this->returnValue($value)). Мы можем использовать вариации этого длинного синтаксиса для достижения более сложного поведения заглушки.
Иногда вы хотите вернуть одно из аргументов вызова метода (без изменений) в качестве результата вызова заглушенного метода. Пример 8.5 показывает, как это можно сделать, используя returnArgument() вместо returnValue().
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testReturnArgumentStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->will($this->returnArgument(0));
// $stub->doSomething('foo') returns 'foo'
$this->assertSame('foo', $stub->doSomething('foo'));
// $stub->doSomething('bar') returns 'bar'
$this->assertSame('bar', $stub->doSomething('bar'));
}
}
При тестировании fluent интерфейса иногда полезно, чтобы заглушенный метод возвращал ссылку на заглушенный объект. Пример 8.6 показывает, как вы можете использовать returnSelf() для этого.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testReturnSelf(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->will($this->returnSelf());
// $stub->doSomething() returns $stub
$this->assertSame($stub, $stub->doSomething());
}
}
Иногда заглушенный метод должен возвращать разные значения в зависимости от предварительно определенного списка аргументов. Вы можете использовать returnValueMap() для создания карты, которая связывает аргументы с соответствующими возвращаемыми значениями. См. Пример 8.7 для примера.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testReturnValueMapStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Create a map of arguments to return values.
$map = [
['a', 'b', 'c', 'd'],
['e', 'f', 'g', 'h']
];
// Configure the stub.
$stub->method('doSomething')
->will($this->returnValueMap($map));
// $stub->doSomething() returns different values depending on
// the provided arguments.
$this->assertSame('d', $stub->doSomething('a', 'b', 'c'));
$this->assertSame('h', $stub->doSomething('e', 'f', 'g'));
}
}
Когда заглушенный вызов метода должен возвращать вычисленное значение вместо фиксированного (см. returnValue()) или (неизменного) аргумента (см. returnArgument()), вы можете использовать returnCallback() для возврата заглушенным методом результата вызова функции или метода обратного вызова. См. Пример 8.8 для примера.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testReturnCallbackStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->will($this->returnCallback('str_rot13'));
// $stub->doSomething($argument) returns str_rot13($argument)
$this->assertSame('fbzrguvat', $stub->doSomething('something'));
}
}
Более простая альтернатива настройке метода обратного вызова может заключаться в указании списка желаемых значений возврата. Это можно сделать с помощью метода onConsecutiveCalls(). См. Пример 8.9 для примера.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testOnConsecutiveCallsStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->will($this->onConsecutiveCalls(2, 3, 5, 7));
// $stub->doSomething() returns a different value each time
$this->assertSame(2, $stub->doSomething());
$this->assertSame(3, $stub->doSomething());
$this->assertSame(5, $stub->doSomething());
}
}
Вместо возврата значения заглушенный метод также может вызывать исключение. Пример 8.10 показывает, как использовать throwException() для этого.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubTest extends TestCase
{
public function testThrowExceptionStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->will($this->throwException(new Exception));
// $stub->doSomething() throws Exception
$stub->doSomething();
}
}
В качестве альтернативы вы можете написать заглушку самостоятельно и улучшить свой дизайн по мере продвижения. Широко используемые ресурсы доступны через единый фасад, поэтому вы можете заменить ресурс на заглушку. Например, вместо того, чтобы иметь прямые вызовы к базе данных, разбросанные по всему коду, у вас есть один объект Database, реализующий интерфейс IDatabase. Затем вы можете создать заглушенную реализацию IDatabase и использовать её для тестирования. Вы даже можете создать вариант запуска тестов с заглушенной базой данных или реальной базой данных, так что вы можете использовать свои тесты для локального тестирования во время разработки и интеграционного тестирования с реальной базой данных.
Функциональность, которую необходимо заглушить, имеет тенденцию группироваться в одном объекте, улучшая сплоченность. Представляя функциональность с единым, связным интерфейсом, вы уменьшаете связанность с остальной частью системы.
Объекты-заглушки
Практика замены объекта тестовой двойником, который проверяет ожидания, например, утверждая, что метод был вызван, называется мокированием.
Вы можете использовать объект-заглушку «как точку наблюдения, используемую для проверки косвенных результатов SUT, когда он используется. Обычно объект-заглушка также включает функциональность тестового дубля, т. е. он должен возвращать значения SUT, если тесты еще не провалились, но акцент делается на проверке косвенных результатов. Поэтому объект-заглушка — это гораздо больше, чем просто тестовый дубль плюс утверждения; он используется совершенно по-другому» (Жерар Месарош).
Ограничение: Автоматическая проверка ожиданий
Только объекты-заглушки, сгенерированные в рамках теста, будут автоматически проверяться PHPUnit. Объекты-заглушки, сгенерированные в поставщиках данных, например, или введённые в тест с помощью аннотации @depends, не будут автоматически проверяться PHPUnit.
Вот пример: предположим, мы хотим проверить, что правильный метод, update() в нашем примере, вызывается на объекте, который наблюдает за другим объектом. Пример 8.11 показывает код для Subject и Observer классов, которые являются частью системы тестирования (SUT).
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
class Subject
{
protected $observers = [];
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function attach(Observer $observer)
{
$this->observers[] = $observer;
}
public function doSomething()
{
// Do something.
// ...
// Notify observers that we did something.
$this->notify('something');
}
public function doSomethingBad()
{
foreach ($this->observers as $observer) {
$observer->reportError(42, 'Something bad happened', $this);
}
}
protected function notify($argument)
{
foreach ($this->observers as $observer) {
$observer->update($argument);
}
}
// Other methods.
}
class Observer
{
public function update($argument)
{
// Do something.
}
public function reportError($errorCode, $errorMessage, Subject $subject)
{
// Do something
}
// Other methods.
}
Пример 8.12 демонстрирует, как использовать объект-заглушку для тестирования взаимодействия между Subject и Observer объектами.
Сначала мы используем метод createMock(), предоставляемый классом PHPUnit\Framework\TestCase, чтобы создать объект-заглушку для Observer.
Поскольку мы заинтересованы в проверке того, что метод вызывается и с какими аргументами, мы вводим методы expects() и with() для указания того, как должно выглядеть это взаимодействие.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SubjectTest extends TestCase
{
public function testObserversAreUpdated(): void
{
// Create a mock for the Observer class,
// only mock the update() method.
$observer = $this->createMock(Observer::class);
// Set up the expectation for the update() method
// to be called only once and with the string 'something'
// as its parameter.
$observer->expects($this->once())
->method('update')
->with($this->equalTo('something'));
// Create a Subject object and attach the mocked
// Observer object to it.
$subject = new Subject('My subject');
$subject->attach($observer);
// Call the doSomething() method on the $subject object
// which we expect to call the mocked Observer object's
// update() method with the string 'something'.
$subject->doSomething();
}
}
Метод with() может принимать любое количество аргументов, соответствующее количеству аргументов вызываемого метода. Вы можете указать более сложные ограничения на аргументы метода, чем просто совпадение.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SubjectTest extends TestCase
{
public function testErrorReported(): void
{
// Create a mock for the Observer class, mocking the
// reportError() method
$observer = $this->createMock(Observer::class);
$observer->expects($this->once())
->method('reportError')
->with(
$this->greaterThan(0),
$this->stringContains('Something'),
$this->anything()
);
$subject = new Subject('My subject');
$subject->attach($observer);
// The doSomethingBad() method should report an error to the observer
// via the reportError() method
$subject->doSomethingBad();
}
}
Метод withConsecutive() может принимать любое количество массивов аргументов, в зависимости от вызовов, которые вы хотите протестировать. Каждый массив представляет собой список ограничений, соответствующих аргументам имитируемого метода, как в with().
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class FooTest extends TestCase
{
public function testFunctionCalledTwoTimesWithSpecificArguments(): void
{
$mock = $this->getMockBuilder(stdClass::class)
->setMethods(['set'])
->getMock();
$mock->expects($this->exactly(2))
->method('set')
->withConsecutive(
[$this->equalTo('foo'), $this->greaterThan(0)],
[$this->equalTo('bar'), $this->greaterThan(0)]
);
$mock->set('foo', 21);
$mock->set('bar', 48);
}
}
Ограничение callback() может быть использовано для более сложной проверки аргументов. Это ограничение принимает PHP коллбек в качестве единственного аргумента. PHP коллбек получит аргумент для проверки в качестве единственного аргумента и должен вернуть true, если аргумент проходит проверку, и false в противном случае.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SubjectTest extends TestCase
{
public function testErrorReported(): void
{
// Create a mock for the Observer class, mocking the
// reportError() method
$observer = $this->createMock(Observer::class);
$observer->expects($this->once())
->method('reportError')
->with(
$this->greaterThan(0),
$this->stringContains('Something'),
$this->callback(function($subject)
{
return is_callable([$subject, 'getName']) &&
$subject->getName() == 'My subject';
}
));
$subject = new Subject('My subject');
$subject->attach($observer);
// The doSomethingBad() method should report an error to the observer
// via the reportError() method
$subject->doSomethingBad();
}
}
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class FooTest extends TestCase
{
public function testIdenticalObjectPassed(): void
{
$expectedObject = new stdClass;
$mock = $this->getMockBuilder(stdClass::class)
->setMethods(['foo'])
->getMock();
$mock->expects($this->once())
->method('foo')
->with($this->identicalTo($expectedObject));
$mock->foo($expectedObject);
}
}
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class FooTest extends TestCase
{
public function testIdenticalObjectPassed(): void
{
$cloneArguments = true;
$mock = $this->getMockBuilder(stdClass::class)
->enableArgumentCloning()
->getMock();
// now your mock clones parameters so the identicalTo constraint
// will fail.
}
}
Ограничения показывает ограничения, которые могут быть применены к аргументам методов, а Таблица 8.1 показывает доступные совпадения для указания количества вызовов.
| Совпадение | Значение |
|---|---|
PHPUnit\Framework\MockObject\Matcher\AnyInvokedCount any() | Возвращает совпадение, которое соответствует, когда метод, для которого оно оценивается, выполняется ноль или более раз. |
PHPUnit\Framework\MockObject\Matcher\InvokedCount never() | Возвращает совпадение, которое соответствует, когда метод, для которого оно оценивается, никогда не выполняется. |
PHPUnit\Framework\MockObject\Matcher\InvokedAtLeastOnce atLeastOnce() | Возвращает совпадение, которое соответствует, когда метод, для которого оно оценивается, выполняется по меньшей мере один раз. |
PHPUnit\Framework\MockObject\Matcher\InvokedCount once() | Возвращает совпадение, которое соответствует, когда метод, для которого оно оценивается, выполняется ровно один раз. |
PHPUnit\Framework\MockObject\Matcher\InvokedCount exactly(int $count) | Возвращает совпадение, которое соответствует, когда метод, для которого оно оценивается, выполняется ровно $count раз. |
PHPUnit\Framework\MockObject\Matcher\InvokedAtIndex at(int $index) | Возвращает совпадение, которое соответствует, когда метод, для которого оно оценивается, вызывается в заданный $index. |
Примечание
Параметр $index для совпадения at() относится к индексу, начиная с нуля, во всех вызовах методов для данного объекта-заглушки. Будьте осторожны при использовании этого совпадения, поскольку оно может привести к хрупким тестам, которые слишком тесно связаны с конкретными реализационными деталями.
Как упоминалось в начале, когда значения по умолчанию, используемые методами createStub() и createMock() для создания тестового дубля, не соответствуют вашим потребностям, вы можете использовать метод getMockBuilder($type) для настройки генерации тестового дубля с помощью интерфейса fluent. Вот список методов, предоставляемых создателем Mock:
-
setMethods(array $methods)может быть вызван на объекте Mock Builder, чтобы указать методы, которые должны быть заменены на настраиваемый тестовый дубль. Поведение других методов не меняется. Если вы вызоветеsetMethods(null), то методы не будут заменены. -
setMethodsExcept(array $methods)может быть вызван на объекте Mock Builder, чтобы указать методы, которые не будут заменены на настраиваемый тестовый дубль, заменяя все остальные публичные методы. Это работает как обратноеsetMethods(). -
setConstructorArgs(array $args)может быть вызван для предоставления массива параметров, передаваемого в конструктор исходного класса (который по умолчанию не заменяется на дублирующую реализацию). -
setMockClassName($name)может быть использован для указания имени класса для сгенерированного тестового дубля. -
disableOriginalConstructor()может использоваться для отключения вызова конструктора исходного класса. -
disableOriginalClone()может использоваться для отключения вызова конструктора клонирования исходного класса. -
disableAutoload()может использоваться для отключения__autoload()во время генерации класса тестового дубля.
Prophecy
Prophecy — это «высокоориентированная, но очень мощная и гибкая PHP фреймворк для мокирования объектов. Хотя первоначально он был создан для удовлетворения потребностей phpspec2, он достаточно гибок, чтобы использоваться внутри любого фреймворка тестирования с минимальными усилиями».
PHPUnit имеет встроенную поддержку использования Prophecy для создания тестовых дублей. Пример 8.18 показывает, как тот же тест, показанный в Пример 8.12, может быть выражен с помощью философии Prophecy пророчеств и откровений:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SubjectTest extends TestCase
{
public function testObserversAreUpdated(): void
{
$subject = new Subject('My subject');
// Create a prophecy for the Observer class.
$observer = $this->prophesize(Observer::class);
// Set up the expectation for the update() method
// to be called only once and with the string 'something'
// as its parameter.
$observer->update('something')->shouldBeCalled();
// Reveal the prophecy and attach the mock object
// to the Subject.
$subject->attach($observer->reveal());
// Call the doSomething() method on the $subject object
// which we expect to call the mocked Observer object's
// update() method with the string 'something'.
$subject->doSomething();
}
}
Обратитесь к документации по Prophecy для получения дополнительной информации о создании, настройке и использовании дублей, шпионов и подстановок с помощью этого альтернативного фреймворка для тестовых дублей.
Моделирование трейтов и абстрактных классов
Метод getMockForTrait() возвращает объект-модель, использующий указанный трейт. Все абстрактные методы данного трейта моделируются. Это позволяет тестировать конкретные методы трейта.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
trait AbstractTrait
{
public function concreteMethod()
{
return $this->abstractMethod();
}
public abstract function abstractMethod();
}
final class TraitClassTest extends TestCase
{
public function testConcreteMethod(): void
{
$mock = $this->getMockForTrait(AbstractTrait::class);
$mock->expects($this->any())
->method('abstractMethod')
->will($this->returnValue(true));
$this->assertTrue($mock->concreteMethod());
}
}
Метод getMockForAbstractClass() возвращает объект-модель для абстрактного класса. Все абстрактные методы данного абстрактного класса моделируются. Это позволяет тестировать конкретные методы абстрактного класса.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
abstract class AbstractClass
{
public function concreteMethod()
{
return $this->abstractMethod();
}
public abstract function abstractMethod();
}
final class AbstractClassTest extends TestCase
{
public function testConcreteMethod(): void
{
$stub = $this->getMockForAbstractClass(AbstractClass::class);
$stub->expects($this->any())
->method('abstractMethod')
->will($this->returnValue(true));
$this->assertTrue($stub->concreteMethod());
}
}
Моделирование и создание заглушек для веб-сервисов
Когда ваше приложение взаимодействует с веб-сервисом, вы хотите протестировать его, не взаимодействуя с ним напрямую. Для создания заглушек и моделей веб-сервисов можно использовать getMockFromWsdl(), как getMock() (см. выше). Единственное отличие в том, что getMockFromWsdl() возвращает заглушку или модель на основе описания веб-сервиса в WSDL, а getMock() возвращает заглушку или модель на основе PHP-класса или интерфейса.
Пример 8.21 демонстрирует, как можно использовать getMockFromWsdl() для создания заглушки, например, для веб-сервиса, описанного в GoogleSearch.wsdl.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class GoogleTest extends TestCase
{
public function testSearch(): void
{
$googleSearch = $this->getMockFromWsdl(
'GoogleSearch.wsdl', 'GoogleSearch'
);
$directoryCategory = new stdClass;
$directoryCategory->fullViewableName = '';
$directoryCategory->specialEncoding = '';
$element = new stdClass;
$element->summary = '';
$element->URL = 'https://phpunit.de/';
$element->snippet = '...';
$element->title = '<b>PHPUnit</b>';
$element->cachedSize = '11k';
$element->relatedInformationPresent = true;
$element->hostName = 'phpunit.de';
$element->directoryCategory = $directoryCategory;
$element->directoryTitle = '';
$result = new stdClass;
$result->documentFiltering = false;
$result->searchComments = '';
$result->estimatedTotalResultsCount = 3.9000;
$result->estimateIsExact = false;
$result->resultElements = [$element];
$result->searchQuery = 'PHPUnit';
$result->startIndex = 1;
$result->endIndex = 1;
$result->searchTips = '';
$result->directoryCategories = [];
$result->searchTime = 0.248822;
$googleSearch->expects($this->any())
->method('doGoogleSearch')
->will($this->returnValue($result));
/**
* $googleSearch->doGoogleSearch() will now return a stubbed result and
* the web service's doGoogleSearch() method will not be invoked.
*/
$this->assertEquals(
$result,
$googleSearch->doGoogleSearch(
'00000000000000000000000000000000',
'PHPUnit',
0,
1,
false,
'',
false,
'',
'',
''
)
);
}
}
© 2005–2020 Sebastian Bergmann
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://phpunit.readthedocs.io/en/8.5/test-doubles.html