Тестовые дубликаты
Жерар Мешарош в своей книге «Шаблоны тестирования xUnit» вводит понятие тестовых дублей следующим образом:
Иногда просто сложно протестировать тестируемую систему (SUT), потому что она зависит от других компонентов, которые нельзя использовать в тестовой среде. Это может быть связано с тем, что они недоступны, не вернут необходимые для теста результаты или их выполнение приведет к нежелательным побочным эффектам. В других случаях наша стратегия тестирования требует большего контроля или видимости внутреннего поведения SUT.
Когда мы пишем тест, в котором мы не можем (или не хотим) использовать реальный зависимый компонент (DOC), мы можем заменить его тестовым дубликатом. Тестовый дубликат не обязан вести себя точно так же, как реальный DOC; он просто должен предоставлять тот же API, что и реальный, чтобы SUT думал, что это реальный!
Методы createStub(string $type) и createMock(string $type) могут использоваться в тесте для автоматического создания объекта, который может действовать как тестовый дубликат для указанного исходного типа (интерфейс или расширяемый класс). Этот объект тестового дубликата можно использовать в любом контексте, где ожидается или требуется объект исходного типа.
Ограничение: методы final, private и static
Обратите внимание, что методы final, private и static не могут быть продублированы. Они игнорируются функциональностью тестовых дублей PHPUnit и сохраняют свое исходное поведение, за исключением методов static, которые будут заменены методом, выбрасывающим исключение.
Ограничение: Перечисления
Перечисления (enum) являются final классами и поэтому не могут быть продублированы.
Предпочитайте дублирование интерфейсов дублированию классов
Не только из-за упомянутых выше ограничений, но и для улучшения дизайна вашего программного обеспечения, предпочтительнее дублировать интерфейсы, чем классы.
Тестовые заглушки
Практика замены объекта тестовым дубликатом, который (по желанию) возвращает настроенные значения, называется заглушкой. Вы можете использовать тестовую заглушку, чтобы «заменить реальный компонент, от которого зависит SUT, так что у теста есть контрольная точка для косвенных входных данных SUT. Это позволяет тесту заставить SUT пройти пути, которые он в противном случае не выполнил бы» (Жерар Мешарош).
Создание тестовых заглушек
createStub()
Метод createStub(string $type) возвращает тестовую заглушку для указанного интерфейса или расширяемого класса.
Все методы исходного типа заменяются реализацией, которая возвращает автоматически сгенерированное значение, удовлетворяющее декларации типа возвращаемого значения метода, без вызова исходного метода. Эти методы называются «методами-дубликатами».
Поведение методов-дубликатов можно настроить, используя такие методы, как willReturn() или willThrowException(). Эти методы описаны позже.
createStubForIntersectionOfInterfaces()
Метод createStubForIntersectionOfInterfaces(array $interfaces) можно использовать для создания тестовой заглушки для пересечения интерфейсов на основе списка имён интерфейсов.
Представьте, что у вас есть следующие интерфейсы X и Y:
<?php declare(strict_types=1);
interface X
{
public function m(): bool;
}
<?php declare(strict_types=1);
interface Y
{
public function n(): int;
}
И у вас есть класс, который вы хотите протестировать, с именем Z:
<?php declare(strict_types=1);
final class Z
{
public function doSomething(X&Y $input): bool
{
$result = false;
// ...
return $result;
}
}
Для тестирования Z нам нужен объект, который удовлетворяет типу пересечения X&Y. Мы можем использовать метод createStubForIntersectionOfInterfaces(array $interfaces) для создания тестовой заглушки, которая удовлетворяет X&Y, как показано ниже:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class StubForIntersectionExampleTest extends TestCase
{
public function testCreateStubForIntersection(): void
{
$o = $this->createStubForIntersectionOfInterfaces([X::class, Y::class]);
// $o is of type X ...
$this->assertInstanceOf(X::class, $o);
// ... and $o is of type Y
$this->assertInstanceOf(Y::class, $o);
}
}
createConfiguredStub()
Метод createConfiguredStub() — это удобная обертка вокруг createStub(), которая позволяет настраивать значения возврата с помощью ассоциативного массива (['methodName' => <return value>]):
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class CreateConfiguredStubExampleTest extends TestCase
{
public function testCreateConfiguredStub(): void
{
$o = $this->createConfiguredStub(
SomeInterface::class,
[
'doSomething' => 'foo',
'doSomethingElse' => 'bar',
]
);
// $o->doSomething() now returns 'foo'
$this->assertSame('foo', $o->doSomething());
// $o->doSomethingElse() now returns 'bar'
$this->assertSame('bar', $o->doSomethingElse());
}
}
Настройка тестовых заглушек
willReturn()
Используя метод willReturn(), например, вы можете настроить дублированный метод, чтобы он возвращал указанное значение при вызове. Это настроенное значение должно быть совместимо с объявленным типом возвращаемого значения метода.
Представьте, что у нас есть класс, который мы хотим протестировать, SomeClass, который зависит от Dependency:
<?php declare(strict_types=1);
final class SomeClass
{
public function doSomething(Dependency $dependency): string
{
$result = '';
// ...
return $result . $dependency->doSomething();
}
}
<?php declare(strict_types=1);
interface Dependency
{
public function doSomething(): string;
}
Вот первый пример, как использовать метод createStub(string $type) для создания тестовой заглушки для Dependency, чтобы мы могли тестировать SomeClass без использования реальной реализации Dependency:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SomeClassTest extends TestCase
{
public function testDoesSomething(): void
{
$sut = new SomeClass;
// Create a test stub for the Dependency interface
$dependency = $this->createStub(Dependency::class);
// Configure the test stub
$dependency->method('doSomething')
->willReturn('foo');
$result = $sut->doSomething($dependency);
$this->assertStringEndsWith('foo', $result);
}
}
Ограничение: методы с именем «method»
Приведенный выше пример работает только тогда, когда исходный интерфейс или класс не объявляет метод с именем «method».
Если исходный интерфейс или класс объявляет метод с именем «method», тогда необходимо использовать $stub->expects($this->any())->method('doSomething')->willReturn('foo');.
Устаревание: Дублирование интерфейсов (или классов), имеющих метод с именем «method»
Начиная с PHPUnit 10.3, поддержка дублирования интерфейсов (или классов), имеющих метод с именем «method», находится на стадии мягкого устаревания, то есть устаревание только в документации.
Начиная с PHPUnit 11, дублирование интерфейсов (или классов), имеющих метод с именем «method», будет вызывать предупреждение об устаревании. Поддержка дублирования интерфейсов (или классов), имеющих метод с именем «method», будет удалена в PHPUnit 12.
В приведенном примере мы сначала используем метод createStub() для создания тестовой заглушки, объекта, который выглядит как экземпляр Dependency.
Затем мы используем Fluent Interface, который предоставляет PHPUnit, для указания поведения тестовой заглушки.
«За кулисами» 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), было бы сгенерировано.
Также можно указать список желаемых возвращаемых значений. Вот пример:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class OnConsecutiveCallsExampleTest extends TestCase
{
public function testOnConsecutiveCallsStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willReturn(1, 2, 3);
// $stub->doSomething() returns a different value each time
$this->assertSame(1, $stub->doSomething());
$this->assertSame(2, $stub->doSomething());
$this->assertSame(3, $stub->doSomething());
}
}
willThrowException()
Вместо возврата значения, заглушенный метод также может вызывать исключение. Вот пример, демонстрирующий, как использовать willThrowException() для этого:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ThrowExceptionExampleTest extends TestCase
{
public function testThrowExceptionStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willThrowException(new Exception);
// $stub->doSomething() throws Exception
$stub->doSomething();
}
}
willReturnArgument()
Иногда нужно вернуть одно из аргументов вызова метода (без изменений) в качестве результата вызова заглушенного метода. Вот пример, демонстрирующий, как это можно сделать с помощью willReturnArgument():
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ReturnArgumentExampleTest extends TestCase
{
public function testReturnArgumentStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willReturnArgument(0);
// $stub->doSomething('foo') returns 'foo'
$this->assertSame('foo', $stub->doSomething('foo'));
// $stub->doSomething('bar') returns 'bar'
$this->assertSame('bar', $stub->doSomething('bar'));
}
}
willReturnCallback()
Когда заглушенный вызов метода должен вернуть вычисленное значение вместо фиксированного (см. willReturn()) или (неизменного) аргумента (см. willReturnArgument()), вы можете использовать willReturnCallback(), чтобы заглушенный метод возвращал результат вызова функции или метода обратного вызова. Вот пример:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ReturnCallbackExampleTest extends TestCase
{
public function testReturnCallbackStub(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willReturnCallback('str_rot13');
// $stub->doSomething($argument) returns str_rot13($argument)
$this->assertSame('fbzrguvat', $stub->doSomething('something'));
}
}
willReturnSelf()
При тестировании интерфейса Fluent Interface иногда полезно, чтобы заглушенный метод возвращал ссылку на заглушенный объект. Вот пример, показывающий, как можно использовать willReturnSelf() для достижения этого:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ReturnSelfExampleTest extends TestCase
{
public function testReturnSelf(): void
{
// Create a stub for the SomeClass class.
$stub = $this->createStub(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willReturnSelf();
// $stub->doSomething() returns $stub
$this->assertSame($stub, $stub->doSomething());
}
}
willReturnMap()
Иногда заглушенный метод должен возвращать разные значения в зависимости от предопределенного списка аргументов. Вот пример, демонстрирующий, как использовать willReturnMap() для создания карты, которая сопоставляет аргументы с соответствующими возвращаемыми значениями:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ReturnMapExampleTest extends TestCase
{
public function testReturnMapStub(): 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')
->willReturnMap($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'));
}
}
Свойства с крючками
PHP 8.4 представил языковую возможность свойств с крючками.
В примере ниже показан интерфейс, который объявляет свойство с крючком:
<?php declare(strict_types=1);
interface InterfaceWithGetHookedProperty
{
public string $property { get; }
}
Поведение свойства с крючком property можно настроить следующим образом:
<?php declare(strict_types=1);
use PHPUnit\Framework\MockObject\Runtime\PropertyHook;
use PHPUnit\Framework\TestCase;
final class ExampleTest extends TestCase
{
public function testExample(): void
{
$stub = $this->createStub(
InterfaceWithHookedProperty::class
);
$stub
->method(PropertyHook::get('property'))
->willReturn('value');
$this->assertSame('value', $stub->property);
}
}
В приведенном примере PropertyHook::get('property') для указания того, что мы хотим настроить поведение метода, вызываемого при чтении свойства с именем property.
Объекты-модели
Практика замены объекта двойником для тестирования ожиданий, например, проверки того, что метод был вызван, называется моделированием.
Вы можете использовать объект-модель «в качестве точки наблюдения, используемой для проверки косвенных результатов SUT во время его выполнения. Как правило, объект-модель также включает функциональность тестового заглушки, так как он должен возвращать значения SUT, если он еще не провалил тесты, но акцент делается на проверке косвенных результатов. Поэтому объект-модель — это гораздо больше, чем просто тестовая заглушка плюс утверждения; он используется принципиально иным способом» (Жерар Месарош).
Создание объектов-моделей
createMock()
Метод createMock(string $type) возвращает объект-модель для указанного интерфейса или расширяемого класса.
Все методы исходного типа заменяются реализацией, которая возвращает автоматически сгенерированное значение, удовлетворяющее объявленному типу возвращаемого значения метода, без вызова исходного метода. Эти методы называются «дублированными методами».
Поведение дублированных методов можно настроить, используя методы, такие как willReturn() или willThrowException(). Эти методы описаны в разделе о тестовых заглушках выше.
Ожидания вызовов дублированных методов («метод должен быть вызван со специфицированными аргументами», «метод не должен быть вызван» и т. д.) можно настроить, используя метод expects() объекта-модели.
createMockForIntersectionOfInterfaces()
Метод createMockForIntersectionOfInterfaces(array $interfaces) можно использовать для создания объекта-модели для пересечения интерфейсов на основе списка имён интерфейсов.
Представьте, что у вас есть следующие интерфейсы X и Y:
<?php declare(strict_types=1);
interface X
{
public function m(): bool;
}
<?php declare(strict_types=1);
interface Y
{
public function n(): int;
}
И у вас есть класс, который вы хотите протестировать, с именем Z:
<?php declare(strict_types=1);
final class Z
{
public function doSomething(X&Y $input): bool
{
$result = false;
// ...
return $result;
}
}
Для тестирования Z нам нужен объект, который удовлетворяет типу пересечения X&Y. Мы можем использовать метод createMockForIntersectionOfInterfaces(array $interfaces) для создания тестовой заглушки, которая удовлетворяет X&Y следующим образом:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class MockForIntersectionExampleTest extends TestCase
{
public function testCreateMockForIntersection(): void
{
$o = $this->createMockForIntersectionOfInterfaces([X::class, Y::class]);
// $o is of type X ...
$this->assertInstanceOf(X::class, $o);
// ... and $o is of type Y
$this->assertInstanceOf(Y::class, $o);
}
}
createConfiguredMock()
Метод createConfiguredMock() — это удобная обертка вокруг createMock(), которая позволяет настраивать возвращаемые значения с помощью ассоциативного массива (['methodName' => <return value>]):
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class CreateConfiguredMockExampleTest extends TestCase
{
public function testCreateConfiguredMock(): void
{
$o = $this->createConfiguredMock(
SomeInterface::class,
[
'doSomething' => 'foo',
'doSomethingElse' => 'bar',
],
);
// $o->doSomething() now returns 'foo'
$this->assertSame('foo', $o->doSomething());
// $o->doSomethingElse() now returns 'bar'
$this->assertSame('bar', $o->doSomethingElse());
}
}
getMockForAbstractClass()
Метод getMockForAbstractClass() возвращает объект-модель для абстрактного класса. Все абстрактные методы данного абстрактного класса имитируются. Это позволяет тестировать конкретные методы абстрактного класса.
<?php declare(strict_types=1);
abstract class AbstractClass
{
public function concreteMethod()
{
return $this->abstractMethod();
}
abstract public function abstractMethod();
}
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class AbstractClassTest extends TestCase
{
public function testConcreteMethod(): void
{
$stub = $this->getMockForAbstractClass(AbstractClass::class);
$stub->expects($this->any())
->method('abstractMethod')
->willReturn(true);
$this->assertTrue($stub->concreteMethod());
}
}
Устаревание: getMockForAbstractClass() устарел
Начиная с PHPUnit 10.1, метод getMockForAbstractClass() мягко устарел, то есть его объявление помечено @deprecated, чтобы инструменты IDE и статического анализа могли предупреждать об его использовании.
Начиная с PHPUnit 11, использование метода getMockForAbstractClass() будет вызывать предупреждение об устаревании. Метод будет удалён в PHPUnit 12.
getMockForTrait()
Метод getMockForTrait() возвращает объект-модель, использующий указанный трейт. Все абстрактные методы данного трейта моделируются. Это позволяет тестировать конкретные методы трейта.
<?php declare(strict_types=1);
trait AbstractTrait
{
public function concreteMethod()
{
return $this->abstractMethod();
}
abstract public function abstractMethod();
}
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class AbstractTraitTest extends TestCase
{
public function testConcreteMethod(): void
{
$mock = $this->getMockForTrait(AbstractTrait::class);
$mock->expects($this->any())
->method('abstractMethod')
->willReturn(true);
$this->assertTrue($mock->concreteMethod());
}
}
Устаревание: getMockForTrait() устарел
Начиная с PHPUnit 10.1, метод getMockForTrait() мягко устарел, то есть его объявление помечено @deprecated, чтобы инструменты IDE и статического анализа могли предупреждать об его использовании.
Начиная с PHPUnit 11, использование метода getMockForTrait() будет вызывать предупреждение об устаревании. Метод будет удалён в PHPUnit 12.
getMockFromWsdl()
Когда ваше приложение взаимодействует с веб-службой, вы хотите протестировать его, не взаимодействуя фактически с веб-службой. Для создания заглушек и моделей веб-служб можно использовать метод getMockFromWsdl().
Этот метод возвращает объект-модель на основе описания веб-службы в WSDL, тогда как createMock() возвращает объект-модель на основе интерфейса или класса.
Вот пример, который показывает, как создать заглушку веб-службы, описанной в HelloService.wsdl:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class WsdlStubExampleTest extends TestCase
{
public function testWebserviceCanBeStubbed(): void
{
$service = $this->getMockFromWsdl(__DIR__ . '/HelloService.wsdl');
$service->method('sayHello')
->willReturn('Hello');
$this->assertSame('Hello', $service->sayHello('message'));
}
}
Устаревание: getMockFromWsdl() устарел
Начиная с PHPUnit 10.1, метод getMockFromWsdl() мягко устарел, то есть его объявление помечено @deprecated, чтобы инструменты IDE и статического анализа могли предупреждать об его использовании.
Начиная с PHPUnit 11, использование метода getMockFromWsdl() будет вызывать предупреждение об устаревании. Метод будет удалён в PHPUnit 12.
Настройка Mock-объектов
Вот пример: предположим, что мы хотим проверить, что правильный метод, update() в нашем примере, вызывается на объекте, который наблюдает за другим объектом.
Вот код для класса Subject и интерфейса Observer, которые являются частью Тестируемого Системного Кода (ТСК):
<?php declare(strict_types=1);
final class Subject
{
private array $observers = [];
public function attach(Observer $observer): void
{
$this->observers[] = $observer;
}
public function doSomething(): void
{
// ...
$this->notify('something');
}
private function notify(string $argument): void
{
foreach ($this->observers as $observer) {
$observer->update($argument);
}
}
// ...
}
<?php declare(strict_types=1);
interface Observer
{
public function update(string $argument): void;
}
Вот пример, который демонстрирует, как использовать mock-объект для тестирования взаимодействия между Subject и Observer объектами:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class SubjectTest extends TestCase
{
public function testObserversAreUpdated(): void
{
$observer = $this->createMock(Observer::class);
$observer->expects($this->once())
->method('update')
->with($this->identicalTo('something'));
$subject = new Subject;
$subject->attach($observer);
$subject->doSomething();
}
}
Сначала мы используем метод createMock() для создания mock-объекта для Observer.
Поскольку мы заинтересованы в проверке взаимодействия между двумя объектами (что метод вызывается и с какими аргументами), мы используем методы expects() и with() для указания того, как должно выглядеть это взаимодействие.
Метод with() может принимать любое количество аргументов, соответствующее количеству аргументов вызываемого метода. Вы можете задать более сложные ограничения на аргументы метода, чем просто соответствие.
Ограничения показывает ограничения, которые могут быть применены к аргументам метода, а вот список матчеров, доступных для указания количества вызовов:
any()возвращает матчер, который соответствует, когда метод, для которого он оценивается, выполняется ноль или более разnever()возвращает матчер, который соответствует, когда метод, для которого он оценивается, никогда не выполняетсяatLeastOnce()возвращает матчер, который соответствует, когда метод, для которого он оценивается, выполняется как минимум один разonce()возвращает матчер, который соответствует, когда метод, для которого он оценивается, выполняется ровно один разatMost(int $count)возвращает матчер, который соответствует, когда метод, для которого он оценивается, выполняется не более$countразexactly(int $count)возвращает матчер, который соответствует, когда метод, для которого он оценивается, выполняется ровно$countраза
API MockBuilder
Как упоминалось ранее, когда значения по умолчанию, используемые методами createStub() и createMock() для генерации тестового дубликата, не соответствуют вашим потребностям, вы можете использовать метод getMockBuilder($type) для настройки генерации тестового дубликата с помощью интерфейса fluent.
setMockClassName()
setMockClassName($name) можно использовать для указания имени класса для генерируемого тестового дубликата.
Устарело: setMockClassName() устарел
Начиная с PHPUnit 10.3, метод setMockClassName() имеет статус мягкого устаревания, т.е. его объявление помечено @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о его использовании.
Начиная с PHPUnit 11, использование метода setMockClassName() будет вызывать предупреждение об устаревании. Метод будет удален в PHPUnit 12.
setConstructorArgs()
setConstructorArgs(array $args) можно вызвать для предоставления массива параметров, который передается в конструктор исходного класса (который по умолчанию не заменяется на дублирующую реализацию).
disableOriginalConstructor()
disableOriginalConstructor() можно использовать для отключения вызова конструктора исходного класса.
enableOriginalConstructor() можно использовать для явного указания на необходимость вызова конструктора исходного класса (по умолчанию).
disableOriginalClone()
disableOriginalClone() можно использовать для отключения вызова конструктора клонирования исходного класса.
enableOriginalClone() можно использовать для явного указания на необходимость вызова конструктора клонирования исходного класса (по умолчанию).
enableArgumentCloning()
enableArgumentCloning() можно использовать для включения клонирования аргументов, передаваемых в дублированные методы.
disableArgumentCloning() можно использовать для явного указания на то, что аргументы, передаваемые в дублированные методы, не должны клонироваться (по умолчанию).
Устарело: enableArgumentCloning() и disableArgumentCloning() устарели
Начиная с PHPUnit 10.1, методы enableArgumentCloning() и disableArgumentCloning() имеют статус мягкого устаревания, т.е. их объявления помечены @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о их использовании.
Начиная с PHPUnit 11, использование методов enableArgumentCloning() и disableArgumentCloning() будет вызывать предупреждение об устаревании. Методы будут удалены в PHPUnit 12.
disableAutoReturnValueGeneration()
disableAutoReturnValueGeneration() можно использовать для отключения автоматической генерации возвращаемых значений, когда возвращаемое значение не настроено.
enableAutoReturnValueGeneration() можно использовать для явного указания на то, что автоматическая генерация возвращаемых значений, когда возвращаемое значение не настроено, включена (по умолчанию).
disallowMockingUnknownTypes()
disallowMockingUnknownTypes() можно использовать для запрета дублирования неизвестных типов.
allowMockingUnknownTypes() можно использовать для явного указания на то, что дублирование неизвестных типов разрешено (по умолчанию).
Устарело: disallowMockingUnknownTypes() и allowMockingUnknownTypes() устарели
Начиная с PHPUnit 10.1, методы disallowMockingUnknownTypes() и allowMockingUnknownTypes() имеют статус мягкого устаревания, т.е. их объявления помечены @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о их использовании.
Начиная с PHPUnit 11, использование методов disallowMockingUnknownTypes() и allowMockingUnknownTypes() будет вызывать предупреждение об устаревании. Методы будут удалены в PHPUnit 12.
disableAutoload()
disableAutoload() можно использовать для отключения функциональности автоматической загрузки PHP во время генерации класса тестового дубликата.
enableAutoload() можно использовать для явного указания на то, что функциональность автоматической загрузки PHP должна быть включена (по умолчанию).
Устарело: disableAutoload() и enableAutoload() устарели
Начиная с PHPUnit 10.1, методы disableAutoload() и enableAutoload() имеют статус мягкого устаревания, т.е. их объявления помечены @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о их использовании.
Начиная с PHPUnit 11, использование методов disableAutoload() и enableAutoload() будет вызывать предупреждение об устаревании. Методы будут удалены в PHPUnit 12.
enableProxyingToOriginalMethods()
enableProxyingToOriginalMethods() можно использовать для включения вызова оригинальных методов. Объект, который будет использоваться для вызова оригинальных методов, должен быть настроен с помощью setProxyTarget().
disableProxyingToOriginalMethods() можно использовать для явного указания на то, что оригинальные методы не вызываются (по умолчанию).
onlyMethods()
onlyMethods(array $methods) можно вызвать на объекте Mock Builder для указания методов, которые должны быть заменены конфигурируемым тестовым дубликатом. Поведение других методов не изменяется. Указанные методы должны существовать в классе, который подменяется.
addMethods()
addMethods(array $methods) можно вызвать на объекте Mock Builder для указания методов, которых нет в интерфейсе или классе, который подменяется. Методы, которые существуют в интерфейсе или классе, остаются неизменными.
Устарело: addMethods() устарел
Начиная с PHPUnit 10.1, метод addMethods() имеет статус мягкого устаревания, т.е. его объявление помечено @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о его использовании.
Начиная с PHPUnit 11, использование метода addMethods() будет вызывать предупреждение об устаревании. Метод будет удален в PHPUnit 12.
getMock()
getMock() генерирует и возвращает объект-модель на основе конфигурации, выполненной с помощью предыдущих вызовов методов. Вызов getMock() должен быть последним в цепочке методов.
getMockForAbstractClass()
getMockForAbstractClass() генерирует и возвращает объект-модель на основе конфигурации, выполненной с помощью предыдущих вызовов методов. Вызов getMockForAbstractClass() должен быть последним в цепочке методов.
Устарело: getMockForAbstractClass() устарел
Начиная с PHPUnit 10.1, метод getMockForAbstractClass() имеет статус мягкого устаревания, т.е. его объявление помечено @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о его использовании.
Начиная с PHPUnit 11, использование метода getMockForAbstractClass() будет вызывать предупреждение об устаревании. Метод будет удален в PHPUnit 12.
getMockForTrait()
getMockForTrait() генерирует и возвращает объект-заглушку на основе конфигурации, заданной с помощью предыдущих вызовов методов. Вызов getMockForTrait() должен быть последним в цепочке методов.
Устарело: getMockForTrait() устарело
Начиная с PHPUnit 10.1, метод getMockForTrait() мягко устарел, то есть его объявление помечено как @deprecated, чтобы IDE и инструменты статического анализа могли предупреждать о его использовании.
Начиная с PHPUnit 11, использование метода getMockForTrait() вызовет предупреждение об устаревании. Метод будет удален в PHPUnit 12.
Ниже представлен пример, демонстрирующий использование гибкого интерфейса Mock Builder для настройки создания тестовой заглушки. Конфигурация этого тестового дубликата использует те же стандартные значения по умолчанию, что и createStub() и createMock():
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class MockBuilderExampleTest 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());
}
}
Установка свойств с крючками
PHP 8.4 представил языковую функцию свойств с крючками.
В примере ниже показан интерфейс, объявляющий свойство с крючком:
<?php declare(strict_types=1);
interface InterfaceWithSetHookedProperty
{
public string $property { set; }
}
Ожидания для свойства с крючком property можно настроить следующим образом:
<?php declare(strict_types=1);
use PHPUnit\Framework\MockObject\Runtime\PropertyHook;
use PHPUnit\Framework\TestCase;
final class SetHookedPropertyMockExampleTest extends TestCase
{
public function testExample(): void
{
$mock = $this->createMock(
InterfaceWithSetHookedProperty::class,
);
$mock
->expects($this->once())
->method(PropertyHook::set('property'))
->with('value');
$mock->property = 'value';
}
}
В приведённом выше примере используется PropertyHook::set('property'), чтобы указать, что мы хотим настроить ожидание для метода, который вызывается при обращении для записи к свойству с именем property.
© 2005–2025 Sebastian Bergmann
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://docs.phpunit.de/en/12.0/test-doubles.html