VOOZH about

URL: https://deepwiki.com/hypervel/process/6-testing-and-faking

⇱ Testing and Faking | hypervel/process | DeepWiki


Loading...
Menu

Testing and Faking

This page provides an overview of the testing infrastructure in the hypervel/process package, which enables simulation of process execution without spawning actual operating system processes. The faking system allows tests to run quickly, deterministically, and without external dependencies while verifying that application code interacts with processes as expected.

This page covers the architecture and components of the testing system. For detailed information about specific aspects:

Purpose and Architecture

The testing infrastructure serves three primary functions:

FunctionImplementationLocation
Fake Handler SystemIntercepts process execution and returns simulated resultsFactory::fake(), Factory::$fakeHandlers
Recording SystemCaptures all process executions during testsFactory::record(), Factory::$recorded
Assertion APIVerifies expected process interactions occurredFactory::assertRan(), Factory::assertRanTimes(), etc.

The architecture uses polymorphism through contracts (ProcessResultContract, InvokedProcessContract) to ensure fake implementations match the API of real implementations. This allows application code to remain unchanged during testing.

Sources: src/Factory.php1-271

Core Testing Components

The following diagram maps the major testing components to their specific classes and responsibilities:


Component Mapping to Code Entities

Sources: src/Factory.php1-271 src/FakeProcessResult.php1-165 src/FakeProcessDescription.php1-189 src/FakeProcessSequence.php1-93

Execution Flow: Real vs Fake

The Factory class controls whether processes execute against the real operating system or against fake handlers:


Handler Resolution Logic

The Factory class matches commands to handlers using the following priority:

  1. Exact command match: Handler keyed by specific command string
  2. Wildcard match: Handler keyed by '*'
  3. No match + strict mode: Throws exception
  4. No match + lenient mode: Falls back to real execution

Sources: src/Factory.php76-99 src/Factory.php134-147

Handler Return Types

Fake handlers (closures registered via Factory::fake()) can return six different types:

Return TypeConversionUse Case
intnew FakeProcessResult(exitCode: $int)Simplest fake, exit code only
string or arraynew FakeProcessResult(output: $value)Common case, just output
ProcessResultUsed directlyFull control over result
FakeProcessDescription$desc->toProcessResult($command)Complex behavior (iterations, streaming)
FakeProcessSequence$sequence() returns next resultDifferent result per call
ThrowableThrown immediatelySimulate exceptions

Example Handler Registrations


Sources: src/Factory.php76-99

Recording and Assertion Workflow

The following diagram shows how the recording and assertion systems work together:


Recording Array Structure

Each entry in Factory::$recorded is a two-element array:


Assertions iterate through this array to verify expected interactions.

Sources: src/Factory.php104-129 src/Factory.php150-222

Key Classes and Methods

Factory Class

The Factory class in src/Factory.php manages the entire testing system:

MethodPurposeLines
fake()Enable faking and register handlers76-99
result()Create a FakeProcessResult46-53
describe()Create a FakeProcessDescription builder58-61
sequence()Create a FakeProcessSequence68-71
isRecording()Check if faking is enabled104-107
recordIfRecording()Conditionally record process112-119
record()Store process execution124-129
preventStrayProcesses()Enable strict mode134-139
preventingStrayProcesses()Check strict mode status144-147
assertRan()Assert process was executed152-164
assertRanTimes()Assert execution count169-184
assertNotRan()Assert process was not executed189-201
assertDidntRun()Alias for assertNotRan()206-209
assertNothingRan()Assert no processes executed214-222

Sources: src/Factory.php1-271

FakeProcessResult Class

The FakeProcessResult class in src/FakeProcessResult.php implements ProcessResultContract to simulate completed processes:

Property/MethodTypePurposeLines
$commandstringCommand that was executed32
$exitCodeintProcess exit code33
$outputstringStandard output16
$errorOutputstringError output20
__construct()Initialize with output/exit code31-39
normalizeOutput()Convert array/string to normalized string44-58
command()stringGet command63-66
successful()boolCheck if exit code is 079-82
failed()boolCheck if exit code is non-zero87-90
exitCode()intGet exit code95-98
output()stringGet standard output103-106
errorOutput()stringGet error output119-122
throw()Throw if failed137-150
throwIf()Conditionally throw if failed157-164

Output Normalization

The normalizeOutput() method src/FakeProcessResult.php44-58 ensures consistent output formatting:

  • Strings: Right-trim newlines, add single trailing newline
  • Arrays: Each element becomes a line with trailing newline
  • Empty values: Empty string

Sources: src/FakeProcessResult.php1-165

FakeProcessDescription Class

The FakeProcessDescription class in src/FakeProcessDescription.php provides a fluent builder for complex fake behavior:

Property/MethodTypePurposeLines
$processId?intSimulated process ID16
$outputarrayOutput buffer with types23
$exitCodeintExit code28
$runIterationsintTimes to report "running"33
id()Set process ID38-43
output()Add standard output line48-59
errorOutput()Add error output line64-75
exitCode()Set exit code118-123
iterations()Set run iterations128-131
runsFor()Set run iterations136-141
toProcessResult()Convert to FakeProcessResult154-162

Output Buffer Structure

Each entry in $output is an array with:


Sources: src/FakeProcessDescription.php1-189

FakeProcessSequence Class

The FakeProcessSequence class in src/FakeProcessSequence.php returns different results on successive invocations:

Property/MethodTypePurposeLines
$processesarrayQueue of results24
$failWhenEmptyboolThrow when empty25
$emptyProcessDefault when empty15
__construct()Initialize with processes23-27
push()Add result to sequence32-37
whenEmpty()Set default result42-48
dontFailWhenEmpty()Allow empty sequence63-66
isEmpty()boolCheck if depleted71-74
__invoke()Get next result81-92

Invocation Behavior

When the sequence is invoked via __invoke():

  1. If empty and $failWhenEmpty is true: throws OutOfBoundsException
  2. If empty and $failWhenEmpty is false: returns $emptyProcess or new FakeProcessResult()
  3. Otherwise: shifts and returns first element from $processes

Sources: src/FakeProcessSequence.php1-93

Integration with PendingProcess

The PendingProcess class integrates with the faking system through:

  1. Fake Handler Storage: PendingProcess receives $fakeHandlers from Factory via withFakeHandlers() method
  2. Handler Resolution: Before executing, checks for matching fake handler
  3. Recording: After execution (real or fake), calls Factory::recordIfRecording()

This integration is transparent to application code, which simply calls run() or start() and receives either a real or fake result.

Sources: src/Factory.php255-258

Benefits of the Testing System

BenefitDescription
SpeedNo actual process spawning, tests complete in milliseconds
DeterminismFake results are predictable, eliminating flaky tests
IsolationTests don't depend on external binaries, file systems, or OS behavior
Edge CasesEasy to simulate timeouts, errors, and unusual output patterns
VerificationAssertions confirm expected process interactions occurred
FlexibilitySix handler return types cover simple to complex scenarios