Spec-Zone.ru › PHPUnit 9

Тестовые двойники

Жерар Мезарош вводит понятие тестовых двойников в Meszaros2007 так:

Жерар Мезарош:

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

Когда мы пишем тест, в котором мы не можем (или не хотим) использовать реальный зависимый компонент (DOC), мы можем заменить его тестовым двойником. Тестовый двойник не обязан вести себя точно так же, как реальный DOC; он просто должен предоставлять тот же API, что и реальный, чтобы SUT думал, что это реальный!

Методы createStub($type), createMock($type), и getMockBuilder($type) библиотеки PHPUnit могут использоваться в тесте для автоматического создания объекта, который может выступать в качестве тестового двойника для указанного исходного типа (интерфейса или имени класса). Этот объект тестового двойника может использоваться в любом контексте, где ожидается или требуется объект исходного типа.

Методы createStub($type) и createMock($type) немедленно возвращают объект тестового двойника для указанного типа (интерфейса или класса). Создание этого тестового двойника выполняется с использованием лучших практик по умолчанию. Методы __construct() и __clone() исходного класса не выполняются, а аргументы, передаваемые методу тестового двойника, не будут клонированы. Если эти значения по умолчанию вам не подходят, вы можете использовать метод getMockBuilder($type) для настройки создания тестового двойника с помощью флюэнт-интерфейса.

По умолчанию все методы исходного класса заменяются на реализацию-заглушку, которая возвращает 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, чтобы указать поведение для заглушки. По сути, это означает, что вам не нужно создавать несколько временных объектов и подключать их позже. Вместо этого вы цепляете вызовы методов, как показано в примере. Это приводит к более удобочитаемому и «плавному» коду.

Пример 8.1 Класс, который мы хотим подставить
<?php declare(strict_types=1);
class SomeClass
{
    public function doSomething()
    {
        // Do something.
    }
}
Пример 8.2 Подстановка вызова метода для возврата фиксированного значения
<?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() автоматически и рекурсивно подставляет значения возврата на основе типа возврата метода. Рассмотрим пример ниже:

Пример 8.3 Метод с объявлением типа возврата
<?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().

Пример 8.4 Можно использовать API Mock Builder для настройки сгенерированного класса тест-дубликата
<?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().

Пример 8.5 Подстановка вызова метода для возврата одного из аргументов
<?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().

Пример 8.6 Подстановка вызова метода для возврата ссылки на заглушенный объект
<?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 для примера.

Пример 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 для примера.

Пример 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 для примера.

Пример 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().

Пример 8.10 Подстановка вызова метода для генерации исключения
<?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).

Пример 8.11 Классы Предмет и Наблюдатель, которые являются частью системы тестирования (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() для указания, как должно выглядеть это взаимодействие.

Пример 8.12 Тестирование, что метод вызывается один раз и со специфическим аргументом
<?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() может принимать любое количество аргументов, соответствующее количеству аргументов вызываемого метода. Вы можете указать более сложные ограничения на аргументы метода, чем просто совпадение.

Пример 8.13 Тестирование, что метод вызывается с несколькими аргументами, ограниченными различными способами
<?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().

Пример 8.14 Тестирование, что метод вызывается дважды со специфическими аргументами.
<?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 в противном случае.

Пример 8.15 Более сложная проверка аргументов
<?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();
    }
}
Пример 8.16 Тестирование, что метод вызывается один раз и с идентичным объектом, который был передан
<?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);
    }
}
Пример 8.17 Создать объект-заглушку с включенными параметрами клонирования
<?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 показывает доступные совпадения для указания количества вызовов.

Таблица 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() во время генерации класса объекта-заглушки.

Мокирование трейтов и абстрактных классов

Метод getMockForTrait() возвращает объект-заглушку, использующий указанный трейт. Все абстрактные методы данного трейта мокируются. Это позволяет тестировать конкретные методы трейта.

Пример 8.18 Тестирование конкретных методов трейта
<?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() возвращает объект-заглушку для абстрактного класса. Все абстрактные методы данного абстрактного класса мокируются. Это позволяет тестировать конкретные методы абстрактного класса.

Пример 8.19 Тестирование конкретных методов абстрактного класса
<?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());
    }
}
END_OF_DOCUMENT_MARKER

Моделирование и создание заглушек веб-служб

При тестировании приложения, взаимодействующего с веб-службой, вы хотите протестировать его без фактического взаимодействия с веб-службой. Для создания заглушек и моделей веб-служб можно использовать getMockFromWsdl(), как в примере getMock() (см. выше). Единственное различие в том, что getMockFromWsdl() возвращает заглушку или модель на основе описания веб-службы в WSDL, а getMock() возвращает заглушку или модель на основе PHP-класса или интерфейса.

Пример 8.20 демонстрирует, как getMockFromWsdl() можно использовать для создания заглушки, например, для веб-службы, описанной в GoogleSearch.wsdl.

Пример 8.20 Создание заглушки веб-службы
<?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/9.5/test-doubles.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API