Injecting a fake payment gateway into a functional test usually means a container manipulation in the test setup, which is fragile and runs after the container is compiled.
# config/services_test.yaml
services:
AppGatewayGatewayInterface: '@AppGatewayInMemoryGateway'
AppGatewayInMemoryGateway:
public: true # so the test can reach in and assert
# nothing in the application changes. nothing knows it is a test.
Declaring the alias in the environment’s own configuration means the substitution happens at compile time and every service that depends on the interface gets the double, including ones the test never mentions. Marking the double public is the one deliberate exception to the private-by-default rule, and it is what lets the test assert on what was recorded. This replaces the pattern where a test boots the kernel and calls $container->set(), which stopped working reliably when the container became compiled.