Skip to content

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

Merged
chr-hertel merged 1 commit into
symfony:mainfrom
wachterjohannes:feature/platform-fake-provider
Jun 21, 2026
Merged

[Platform] Add Mock test provider for routing-aware, any-result-type mocks#2123
chr-hertel merged 1 commit 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

Comment thread src/platform/src/Mock/Factory.php Outdated
Comment thread src/platform/src/Mock/Factory.php Outdated
Comment thread src/platform/src/Mock/MockModelClient.php Outdated
Comment thread src/platform/src/Mock/Factory.php Outdated
Comment thread src/platform/src/Mock/ModelCatalog.php Outdated
@wachterjohannes

Copy link
Copy Markdown
Contributor Author

@chr-hertel fixed :)

@wachterjohannes wachterjohannes force-pushed the feature/platform-fake-provider branch from a7158db to 46bd698 Compare June 20, 2026 20:54
@chr-hertel

Copy link
Copy Markdown
Member

The last thing i'm thinking about is merging the namespaces by basically moving this to the Symfony\AI\Platform\Test namespace - next to the InMemoryPlatform - WDYT?

@wachterjohannes

Copy link
Copy Markdown
Contributor Author

The last thing i'm thinking about is merging the namespaces by basically moving this to the Symfony\AI\Platform\Test namespace - next to the InMemoryPlatform - WDYT?

doing it at the moment :)

@wachterjohannes

Copy link
Copy Markdown
Contributor Author

@chr-hertel done

@wachterjohannes wachterjohannes force-pushed the feature/platform-fake-provider branch 2 times, most recently from d669751 to 90cc232 Compare June 21, 2026 21:00

@chr-hertel chr-hertel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's go 👍

@chr-hertel chr-hertel force-pushed the feature/platform-fake-provider branch from 90cc232 to 2e301e8 Compare June 21, 2026 21:19
@chr-hertel

Copy link
Copy Markdown
Member

Thank you @wachterjohannes.

@chr-hertel chr-hertel merged commit 1243cad into symfony:main Jun 21, 2026
7 checks passed
@wachterjohannes wachterjohannes deleted the feature/platform-fake-provider branch June 21, 2026 21:23
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: Reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants