Doubles API
This reference lists double factories, argument matchers, captors, and mock plans.
These signatures are the public API.
Argument
Namespace: Greenlight\Doubles
final class Argument
any()
This matcher accepts all values in its position.
public static function any(): ArgumentMatcher
type()
This matcher accepts instances of the specified class or interface.
It also accepts values when get_debug_type() returns $type.
public static function type(string $type): ArgumentMatcher
PHPDoc:
@template TType of string@param TType $type@return ( $type is 'array' ? ArgumentMatcher<array<array-key, mixed>> : ( $type is 'bool' ? ArgumentMatcher<bool> : ( $type is 'float' ? ArgumentMatcher<float> : ( $type is 'int' ? ArgumentMatcher<int> : ( $type is 'null' ? ArgumentMatcher<null> : ( $type is 'string' ? ArgumentMatcher<string> : ( $type is class-string ? ArgumentMatcher<new<TType>> : ArgumentMatcher<mixed> ) ) ) ) ) ) )@throws InvalidDoubleUsage
intersection()
This matcher accepts values that have every specified type.
public static function intersection(string $first, string $second, string ...$rest): ArgumentMatcher
PHPDoc:
@return ArgumentMatcher<mixed>@throws InvalidDoubleUsage
union()
This matcher accepts values that have one or more specified types.
public static function union(string $first, string $second, string ...$rest): ArgumentMatcher
PHPDoc:
@return ArgumentMatcher<mixed>@throws InvalidDoubleUsage
predicate()
This matcher accepts the value when the closure returns true. A declared parameter type rejects incompatible values before the closure runs. The description identifies the constraint in failure messages.
public static function predicate(\Closure $predicate, string $description = 'predicate'): ArgumentMatcher
PHPDoc:
@template T@param \Closure(T): mixed $predicate@return ArgumentMatcher<T>@throws InvalidDoubleUsage
equals()
This matcher uses the same deep equality as Expectation::toEqual().
Use it when with() must compare by value instead of identity.
public static function equals(mixed $value): ArgumentMatcher
PHPDoc:
@template T@param T $value@return ArgumentMatcher<T>
allOf()
This matcher accepts a value when all its matchers accept the value. Greenlight checks the matchers in argument order and stops after a failure.
public static function allOf(
ArgumentMatcher $first,
ArgumentMatcher $second,
ArgumentMatcher ...$rest,
): ArgumentMatcher
PHPDoc:
@template T@param ArgumentMatcher<T> $first@param ArgumentMatcher<T> $second@param ArgumentMatcher<T> ...$rest@return ArgumentMatcher<T>@throws InvalidDoubleUsage
captor()
This matcher accepts all values. It records the value when Greenlight selects the related expectation for the call.
public static function captor(): ArgumentCaptor
ArgumentCaptor
Namespace: Greenlight\Doubles
A captor records the argument in its position. It records the argument when Greenlight selects the related expectation for the call.
matches() always accepts the value and does not record it. Only the
expectation selected for the call can record an argument. Thus, checks of
candidate expectations cannot add values to a captor.
final class ArgumentCaptor implements ArgumentMatcher
PHPDoc:
@template TValue = mixed
matches()
public function matches(mixed $value): bool
describe()
public function describe(): string
values()
public function values(): array
PHPDoc:
@return list<TValue>
value()
public function value(): mixed
PHPDoc:
@return TValue@throws InvalidDoubleUsage
ArgumentMatcher
Namespace: Greenlight\Doubles
An argument constraint for one position in with().
matches() determines if the matcher accepts a value in its position.
Candidate expectations can receive checks for calls that they do not
answer. Thus, matches() must not cause side effects. describe() identifies
the constraint in failure messages.
Use the Argument factories to get matchers.
interface ArgumentMatcher
PHPDoc:
@template-covariant TValue = mixed
matches()
public function matches(mixed $value): bool;
describe()
public function describe(): string;
Doubles
Namespace: Greenlight\Doubles
Creates mocks, stubs, and spies. For intercepted methods, mocks fail on calls without a planned expectation. Each return value needs a configured result. Stubs cause an error for intercepted calls. Spies record intercepted calls to methods without a return value.
A verification failure throws one ExpectationFailed. It contains one
FailureDetail for each unmet expectation. Thus, the reporter shows it in
the same format as an Expect failure.
Doubles supports interfaces and classes that are neither final nor
readonly. Class constructors do not run. Final methods keep their original
implementation. Doubles does not support partial mocks or static interception.
Greenlight disposes injected factories after each test attempt. If you
construct a factory directly, call dispose() to verify its mocks.
final class Doubles implements Disposable
__construct()
public function __construct(?string $proxyDirectory = null)
PHPDoc:
@param string|null $proxyDirectory Directory for generated proxy classes. An empty string is invalid. The default is a project directory in the system temporary directory. A hash of the current working directory identifies it.@throws \InvalidArgumentException if the proxy directory is empty@throws InvalidDoubleUsage if PHP cannot resolve the default working directory
mock()
Creates a strict double. Disposal checks each planned expectation. An intercepted call without an expectation fails the test immediately.
public function mock(string $type, ?\Closure $plan = null): object
PHPDoc:
@template T of object@param class-string<T> $type@param \Closure(MockPlan<T>): void|null $plan@return T@throws InvalidDoubleUsage
stub()
Creates a double that satisfies the specified type. Intercepted calls cause a test error. Use a mock with explicit expectations when a collaborator must supply results.
public function stub(string $type): object
PHPDoc:
@template T of object@param class-string<T> $type@return T@throws InvalidDoubleUsage
spy()
Creates a spy that records intercepted calls and their arguments.
An intercepted method that returns a value causes a test error.
Use callsTo() to get the calls. Use Expect to check them.
public function spy(string $type): object
PHPDoc:
@template T of object@param class-string<T> $type@return T@throws InvalidDoubleUsage
callsTo()
Gets the calls to one method of a double from this factory. The result uses call order. Each entry contains the arguments for one call. The method must exist on the doubled type.
public function callsTo(object $double, string $method): array
PHPDoc:
@return list<list<mixed>>@throws InvalidDoubleUsage
dispose()
Verifies mocks and clears their state when the test scope closes.
One ExpectationFailed contains the details for all unmet expectations.
public function dispose(): void
PHPDoc:
@throws ExpectationFailed
Fake
Namespace: Greenlight\Doubles
Identifies a manual in-memory test implementation.
The interface does not change behavior. It lets reporters and tools identify the object as an intentional fake, not production code under test.
interface Fake
This type does not declare public members.
InvalidDoubleUsage
Namespace: Greenlight\Doubles
Identifies incorrect use of the doubles API. Examples include an
unsupported type or a method that Doubles cannot intercept. Other examples
are a prohibited interaction or a return value without a configured
result.
These conditions are errors in the test code, not expectation failures. Thus, Greenlight reports the test as an error.
final class InvalidDoubleUsage extends \LogicException
stubWasCalled()
public static function stubWasCalled(string $type, string $method): self
returnNotConfigured()
public static function returnNotConfigured(string $type, string $method): self
spyCannotAnswer()
public static function spyCannotAnswer(string $type, string $method): self
noSuchMethod()
public static function noSuchMethod(string $type, string $method): self
noSuchRecordedMethod()
public static function noSuchRecordedMethod(string $type, string $method): self
staticMethod()
public static function staticMethod(string $type, string $method): self
neverMethodRequiresThrow()
public static function neverMethodRequiresThrow(string $type, string $method): self
methodNotPublic()
public static function methodNotPublic(string $type, string $method): self
finalMethod()
public static function finalMethod(string $type, string $method): self
unsupportedReflectionType()
public static function unsupportedReflectionType(string $typeClass): self
parentTypeWithoutParent()
public static function parentTypeWithoutParent(string $context): self
unsupportedNestedReflectionType()
public static function unsupportedNestedReflectionType(string $typeClass): self
cannotDoubleEnum()
public static function cannotDoubleEnum(string $type): self
cannotDoubleReadonly()
public static function cannotDoubleReadonly(string $type): self
cannotDoubleFinal()
public static function cannotDoubleFinal(string $type): self
cannotDoubleTrait()
public static function cannotDoubleTrait(string $type): self
notDoubleable()
public static function notDoubleable(string $type): self
attachHandlerCollision()
public static function attachHandlerCollision(string $class): self
handlerPropertyCollision()
public static function handlerPropertyCollision(string $class): self
defaultValueNotReproducible()
public static function defaultValueNotReproducible(string $parameter, string $class, string $method): self
defaultConstantUnresolvable()
public static function defaultConstantUnresolvable(string $parameter): self
objectDefaultNotReproducible()
public static function objectDefaultNotReproducible(string $parameter, string $class, string $method): self
objectDefaultSourceUnavailable()
public static function objectDefaultSourceUnavailable(string $parameter, string $class, string $method): self
objectDefaultScopeUnavailable()
public static function objectDefaultScopeUnavailable(string $parameter, string $class, string $method): self
proxyDirectoryNotCreated()
public static function proxyDirectoryNotCreated(string $directory, ?string $reason = null): self
proxyFileNotWritten()
public static function proxyFileNotWritten(string $file, \Throwable $cause): self
proxyFileNotLoaded()
public static function proxyFileNotLoaded(string $file, ?\Throwable $cause = null): self
workingDirectoryUnresolved()
public static function workingDirectoryUnresolved(): self
foreignDouble()
public static function foreignDouble(string $class): self
invalidTimes()
public static function invalidTimes(int $count): self
invalidAtLeast()
public static function invalidAtLeast(int $count): self
tooFewPlannedArguments()
public static function tooFewPlannedArguments(
string $selector,
string $type,
string $method,
int $actual,
int $required,
): self
PHPDoc:
@param class-string $type
tooManyPlannedArguments()
public static function tooManyPlannedArguments(
string $selector,
string $type,
string $method,
int $actual,
int $maximum,
): self
PHPDoc:
@param class-string $type
incompatiblePlannedArgumentMatcher()
public static function incompatiblePlannedArgumentMatcher(
string $selector,
string $type,
string $method,
int $position,
string $matcherType,
string $parameter,
string $parameterType,
): self
PHPDoc:
@param class-string $type
tooFewCallArguments()
public static function tooFewCallArguments(string $type, string $method, int $actual, int $required): self
PHPDoc:
@param class-string $type
tooManyCallArguments()
public static function tooManyCallArguments(string $type, string $method, int $actual, int $maximum): self
PHPDoc:
@param class-string $type
conflictingAnswers()
public static function conflictingAnswers(string $method): self
emptySequence()
public static function emptySequence(string $method): self
sequenceExhausted()
public static function sequenceExhausted(string $method, int $count): self
nothingCaptured()
public static function nothingCaptured(): self
invalidCaptorPosition()
public static function invalidCaptorPosition(int $position): self
invalidArgumentType()
public static function invalidArgumentType(): self
invalidArgumentTypeCombination()
public static function invalidArgumentTypeCombination(string $factory): self
compositeArgumentCaptor()
public static function compositeArgumentCaptor(): self
MethodExpectation
Namespace: Greenlight\Doubles
Defines one planned call pattern for a method of a double. The plan specifies the accepted arguments, cardinality, and result.
MockPlan::expects() creates this object. Its fluent plan methods are the
public interface. The call handler and verifier use members that have the
@internal tag.
Bare argument values use strict comparison (===). Use
Argument::equals() to apply deep equality.
final class MethodExpectation
PHPDoc:
@template TTarget of object = object@template TMethod of non-empty-string = non-empty-string
$method
public readonly string $method;
withNoArguments()
public function withNoArguments(): self
PHPDoc:
@throws InvalidDoubleUsage
with()
public function with(mixed $first, mixed ...$rest): self
PHPDoc:
@throws InvalidDoubleUsage
once()
public function once(): self
times()
public function times(int $count): self
PHPDoc:
@throws InvalidDoubleUsage
atLeast()
public function atLeast(int $count): self
PHPDoc:
@throws InvalidDoubleUsage
never()
public function never(): self
andReturns()
public function andReturns(mixed $value): self
PHPDoc:
@throws InvalidDoubleUsage
andReturnsSequence()
Each accepted call consumes the next value. A call after the last value causes an error in the test code.
public function andReturnsSequence(mixed ...$values): self
PHPDoc:
@throws InvalidDoubleUsage
andReturnsUsing()
The closure receives the call arguments. The call returns the value from the closure.
public function andReturnsUsing(\Closure $answer): self
PHPDoc:
@throws InvalidDoubleUsage
andThrows()
public function andThrows(\Throwable $throwable): self
PHPDoc:
@throws InvalidDoubleUsage
captureArgument()
Records the argument at $position each time Greenlight selects this
expectation for a call. The method returns the captor and ends the
fluent chain. Before you call this method, configure the cardinality. If
the doubled method returns a value, configure its result first.
public function captureArgument(int $position = 0): ArgumentCaptor
PHPDoc:
@return ArgumentCaptor<mixed>@throws InvalidDoubleUsage
MockPlan
Namespace: Greenlight\Doubles
Defines the mock plan that Doubles::mock() supplies to its closure.
Use the fluent methods to declare call patterns. The default cardinality is at least one call. The verifier checks each declared pattern when the test scope closes.
final readonly class MockPlan
PHPDoc:
@template TTarget of object = object
any()
Returns the with() wildcard that accepts all values in its position.
public static function any(): ArgumentMatcher
expects()
public function expects(string $method): MethodExpectation
PHPDoc:
@template TMethod of non-empty-string@param TMethod $method@return MethodExpectation<TTarget, TMethod>@throws InvalidDoubleUsage