Reflex provides the abstract test wrapper class
Valvoid\Reflex\Test\Wrapper\Wrapper, which you must extend to create custom
tests. It normalizes groups of tests so they can be executed automatically
by runners.
Naming Rules
In addition to normalizing execution, your tests must be discoverable by
runners. Typically, you organize your tests in directories provided via
configuration. Since these directories may contain files other than tests, the
test files must have the Test.php suffix. For example:
tests/Units: Dir provided via config to the runnerCustomTest.php: File with custom tests.whatever: File the runner ignores.
Within the CustomTest.php file, you expose executable public methods with
the test prefix:
use Valvoid\Reflex\Test\Wrapper;
class CustomTest extends Wrapper
{
public function testSomething(): void {}
}
Note
The runner executes these methods in the order they are defined in the wrapper, from top to bottom.
Lifecycle Hooks
All custom test methods are executed within a fixed lifecycle flow, which you can hook into by overriding the following methods:
init: Initializes the test wrapper state after object construction.prepare: Initializes the test state before method execution.finalize: Evaluates the test state after method execution.drop: Cleans up the test wrapper state before object destruction.
Note
When overriding lifecycle methods, remember to call the corresponding
parent method inside the hook to ensure the internal wrapper state
remains consistent.
Explicit Code Coverage
By default, Reflex collects coverage data for all code that is executed
during a test run, between the lifecycle methods prepare and finalize.
In some cases, tests may execute additional code that should not be part of
the coverage report. To handle this, you can explicitly mark code to be
covered or ignored:
Valvoid\Reflex\Coverage\Events\CoverValvoid\Reflex\Coverage\Events\Inore
public function __construct(Box $box)
{
parent::__construct($box, new Cover(Example::class));
}
Dependency Injection
For abstraction, Reflex uses the
Box DI Container.
This includes instantiating custom tests and resolving their dependencies.
You can add custom dependencies as constructor parameters or access the
container directly via the $box object.
Note
When overriding the constructor, remember to pass the $box instance to
the parent constructor to ensure proper container integration.
Test Doubles
Complex code often depends on other implementations. To isolate such code in your tests, you can fake these dependencies with stubs and mocks. Stubs are predefined objects used to replace dependencies:
createStub: Initialize the object.recycleStub: Reuse the object logic.resetStub: Drop the object logic.
Mocks are similar to stubs but also track and validate interactions:
createMock: Initialize the object.recycleMock: Reuse the object logic.resetMock: Drop the object logic.
Note
All of these methods register the double for the current test. They must be called inside the test method so the wrapper knows which doubles are in use for validation purposes.
Test Validation
Tests are considered successful by default and must explicitly report failures. To validate test results, you can describe valid outcomes or fail a test manually when more complex validation logic is required:
validate: Declare valid value.expectException: Set valid exception.fail: Fail test manually.