Skip to content

[Platform] Add Mock test provider for routing-aware, any-result-type mocks#2123

Open
wachterjohannes wants to merge 3 commits into
symfony:mainfrom
wachterjohannes:feature/platform-fake-provider
Open

[Platform] Add Mock test provider for routing-aware, any-result-type mocks#2123
wachterjohannes wants to merge 3 commits into
symfony:mainfrom
wachterjohannes:feature/platform-fake-provider

Conversation

@wachterjohannes

@wachterjohannes wachterjohannes commented May 28, 2026

Copy link
Copy Markdown
Contributor
Q A
Bug fix? no
New feature? yes
Docs? yes
Issues -
License MIT

Adds a provider-level test mock under Symfony\AI\Platform\Mock that registers like a real bridge, participates in model routing, returns scripted responses of any result type, and records call history for assertions.

Why not just Test\InMemoryPlatform?

Test\InMemoryPlatform is a platform-level fake: it replaces the whole Platform, ignores routing, has no model catalog, and returns text only — perfect for unit tests injecting a PlatformInterface directly. The new Mock provider is provider-level and complementary. Reach for it when a test must:

  • go through real DI / routing (functional tests),
  • coexist with real providers and prove routing picks the mock (multi-provider tests),
  • return non-text results (ObjectResult, StreamResult, ToolCallResult, VectorResult),
  • assert on exactly what the platform sent (recorded call history via getCalls()).

Design

MockModelClient::request() resolves a scripted ResultInterface (or wraps a string in TextResult), records the call, and threads the result through the object slot of the existing InMemoryRawResult. MockResultConverter::convert() pulls it back out and returns it verbatim — so every result type is supported with no per-type conversion code. The embedding-mock case falls out for free by scripting a VectorResult.

Usage

use Symfony\AI\Platform\Mock\Factory;
use Symfony\AI\Platform\Result\ObjectResult;

// string — every call returns a TextResult
$platform = Factory::createPlatform("Hello world");
$platform->invoke("any-model", "question")->asText(); // "Hello world"

// map keyed by model name
$platform = Factory::createPlatform(["gpt-4o" => "answer"]);

// closure — branch on payload/options
$platform = Factory::createPlatform(
    static fn ($model, $payload, $options) => isset($options["response_format"])
        ? new ObjectResult((object) ["ok" => true])
        : "plain text",
);

It lives in platform core (not under src/Bridge/, which splitsh.json excludes from the symfony/ai-platform package), so it ships with the platform exactly like Test\InMemoryPlatform.

Scope / follow-ups

  • Out: ai-bundle config node (framework.ai.platform.mock) — closures cannot be expressed in YAML; most consumers register the mock in a test kernel / compiler pass. The PHP API is what unblocks them.
  • Out: a mock Contract/normalizer (the mock records payloads raw) and fault injection (scripted exceptions) — easy to add later.

Verification

  • vendor/bin/phpunit tests/Mock — 21 tests, 38 assertions, green.
  • vendor/bin/phpstan analyse — clean.
  • php-cs-fixer — clean.

@OskarStark

Copy link
Copy Markdown
Contributor

Shall we name it to Mock? AFAIK this is more the Symfony naming

@wachterjohannes wachterjohannes force-pushed the feature/platform-fake-provider branch from b44dd7c to 42fc0c5 Compare June 1, 2026 06:20
@wachterjohannes wachterjohannes changed the title [Platform] Add Fake test provider for routing-aware, any-result-type fakes [Platform] Add Mock test provider for routing-aware, any-result-type mocks Jun 1, 2026
@wachterjohannes

Copy link
Copy Markdown
Contributor Author

Shall we name it to Mock? AFAIK this is more the Symfony naming

Good call 👍

done — renamed Fake → Mock, have also done the same rename to the stacked PRs: #2128 and #2129

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New feature Platform Issues & PRs about the AI Platform component Status: Needs Review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants