I am trying to use BrowserTestBase to write a functional test for a Form. The form populates some form elements with data retrieved from an external site. The client for this external site is injected into the form as a Drupal 8 service. The client uses Guzzle, and I'm building the mock client using code similar to the following one.

$myClient = new MyClient(Drupal::configFactory(), [
  'handler' => HandlerStack::create(
    new MockHandler([
      new Response(200, ['X-Foo' => 'Bar'], 'Hello, World')
  'base_uri' => 'http://example.com/api/',

I've tried doing this in the test class to assign my mock client to the service.

$this->container->set('my.service', $mockClient);

I've tried placing this assignment in setUp() as well as the testMyForm() method itself, but the container passed to the form's create() method doesn't contain $mockClient.


After digging into the code I discovered that parameters and services may be initialized in the test-site context by adding them inside testing.services.yml and placing that in the default site folder. In my test I used:

    class: GuzzleHttp\HandlerStack
    factory: GuzzleHttp\HandlerStack::create
      - '@browser_test.mock_handler'
    class: GuzzleHttp\Handler\MockHandler
    class: Drupal\mymodule\Client\MyClient
      - '@config.factory'
        base_uri: 'http://localhost/test/'
        handler: '@browser_test.handler_stack'

This overrode the client (which solves part of the problem), however I'm still unable to inject mock responses into MockHandler from the test class. I tried:

/** @var MockHandler $handlerStack */
$handler = $this->container->get('browser_test.mock_handler');
$handler->append(new Response(200, ['X-Foo' => 'Bar'], 'Hello, World'));


But MockHandler is throwing an exception because Mock queue is empty.

  • I also was trying this earlier in the week. The docs state that this is how you'd override it, but I was not seeing that to be the case. Interested in any answers.
    – Kevin
    Dec 13 '19 at 20:44
  • 1
    For reference... drupal.stackexchange.com/questions/289129/…
    – Kevin
    Dec 14 '19 at 0:37
  • It looks like params and services can be initialized by adding a sites/default/testing.services.yml file to the site. This file gets copied to the site provisioned for the functional test (see FunctionalTestSetupTrait::prepareSettings(). However it's still unclear if it's possible to inject mock responses to Guzzle requests from the Test class to the test site.
    – J Webb
    Dec 14 '19 at 5:50
  • 4
    Does this answer your question? Mock a service while running a BrowserTest?
    – leymannx
    Dec 14 '19 at 16:18
  • I it is not possible to modify the guzzle options after the guzzle client has been initiated. This isn't necessarily a duplicate, but I think overriding the output of the service's method like @leymannx suggests is appropriate rather than try to test the internals of Guzzle.
    – mradcliffe
    Dec 16 '19 at 20:35