Skip to content

addition: Saloon testing utils without global state - #33

Merged
remipelhate merged 16 commits into
mainfrom
addition/saloon-testing-utils-without-global-state
Sep 8, 2026
Merged

remipelhate merged 16 commits into
mainfrom
addition/saloon-testing-utils-without-global-state

Conversation

@remipelhate

@remipelhate remipelhate commented Sep 8, 2026

Copy link
Copy Markdown
Member

Before moving towards hexagonal architecture, we developed some extensions on Saloon's testing utils. While those utils are mice to work with, they do come with the downside of relying on global state, often not allowing us to write pur unit tests for any implementation that sends Saloon requests.

This PR proposes a set of custom testing utils that don't build upon Saloon's native solution, but are more in line with our current standards.

With the new testing utils, this excerpt from the source code:

// extends App\Testing\TestCase

$connector = new CoreBackendConnector();
$project = new ProjectFactory()->makeOne();
FakeResponse::make([])(PostProjectRequest::class);

new ProjectRepositoryUsingCoreBackend($connector)->save($project);

$this->assertThat(
    new PostProjectRequest(),
    new WasSent($connector)->once(),
);

... can be rewritten to:

// extends PHPUnit\Framework\TestCase

$project = new ProjectFactory()->makeOne();
$expectedRequest = new PostProjectRequest();
$connector = new FakeResponseConnector(FakeResponse::ok($expectedRequest))->spy();

new ProjectRepositoryUsingCoreBackend($connector)->save($project);

$connector->send->assert(
    new WasCalled(new WithRequest($expectedRequest))->once(),
);

The only change required on implementation side is to typehint Saloon\Http\Connector instead of CoreBackendConnector directly. This does mean that the implementation has to be bound to the container explicitly.

Deprecated

  • Craftzing\TestBench\Saloon\Doubles\FakeConnector has been deprecated in favour of Craftzing\TestBench\Saloon\Doubles\FakeResponseConnector.
  • Craftzing\TestBench\Saloon\DataProviders\FakeResponse has been deprecated in favour or a more generic Craftzing\TestBench\PHPUnit\DataProviders\HttpStatusCode data provider.
  • Craftzing\TestBench\Saloon\Constraints\WasSent has been deprecated in favour of Craftzing\TestBench\Saloon\Doubles\FakeResponseConnector.

Added

  • Craftzing\TestBench\Saloon\Doubles\FakeResponseConnector completely bypasses Saloon's native MockClient implementation and solely relies on Craftzing\TestBench\Saloon\Doubles\FakeResponse instances.
  • Craftzing\TestBench\Saloon\Doubles\SpyConnector is a new Connector test double that can be used to spy on the send method. It can be used as a decorator or standalone implementation and is mostly useful to make assertions that the send method was never called.
  • Craftzing\TestBench\PHPUnit\Constraint\PublicPropertiesComparator has been added as an alternative to PhpUnit's default ObjectComparator, which compares all properties regardless of their visibility or whether they're virtual. PublicPropertiesComparator in contrary can be registered to only check the public properties of an object. E.g.:
#[Before]
public function enableComparingSaloonRequests(): void
{
    $this->registerComparator(new PublicPropertiesComparator(Request::class));
}

@remipelhate
remipelhate requested a review from fowbi September 8, 2026 11:46

@fowbi fowbi left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good 👍🏻

@remipelhate
remipelhate merged commit fefb1fb into main Sep 8, 2026
5 checks passed
@remipelhate
remipelhate deleted the addition/saloon-testing-utils-without-global-state branch September 8, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants