2

I am trying to test the output of a controller that returns some information in a given page. This controller has a custom http client injected into it.

I want to create a BrowserTest that can navigate to a fake node, and then test for certain text or values. I also want to change the mock to return different values, so I can further test the output to account for those cases.

I tried:

    $client = $this->getMockBuilder('\Drupal\mymodule\Client\AuthorizeClient')
      ->disableOriginalConstructor()
      ->getMock();
    $client->expects($this->any())
      ->method('request')
      ->with('w12345', FALSE)
      ->willReturn([]);

    $this->container->set('mymodule.auth_client', $client);

But I get errors in the test that refer to the original class, and not the one I am trying to replace. I looked around in the core but wasn't really able to find what I was looking for. Does it make sense to do this? Is there a way to do a Kernel test to test responses from the route in question?

1 Answer 1

1

I could not quite get my mocked service to be used from the container as per the docs, so I resulted to doing this.

I don't really need a BrowserTest per se, as I just want to ensure the Response object contains what it should. I create a client mock and instantiate the controller object myself:

<?php

namespace Drupal\Tests\mymodule\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\mymodule\Controller\AuthorizeController;
use Drupal\node\Entity\Node;
use Drupal\file\Entity\File;
use Drupal\Core\File\FileSystem;

/**
 * Tests the AuthorizeController controller.
 *
 * @group mymodule
 */
class AuthorizeControllerTest extends KernelTestBase {

  /**
   * @var array
   */
  public static $modules = ['system', 'node', 'field', 'mymodule', 'file', 'mymodule_authtest', 'user', 'text'];

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    parent::setUp();

    $this->installConfig(['node', 'user', 'mymodule_authtest', 'file']);
    $this->installSchema('file', ['file_usage']);
    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installEntitySchema('file');

    $module_path = drupal_get_path('module', 'mymodule_authtest');

    $uri = $this->container->get('file_system')->copy("$module_path/fixtures/pdf/foo.pdf", 'public://foo.pdf', FileSystem::EXISTS_REPLACE);

    $file = File::Create([
      'uri' => $uri,
    ]);
    $file->save();

    $node = Node::create(array(
      'title' => t('Test Paper'),
      'type' => 'working_paper',
      'language' => 'en',
      'field_id' => 'w12345',
      'field_paper_working_paper' => $file->id(),
    ));
    $node->save();
  }

  /**
   * Test different scenarios and responses from our controller.
   */
  public function testControllerResponse() {
    $node = $this->container->get('entity_type.manager')->getStorage('node')->load(1);

    $client = $this->getMockClient(1, 3, 3);
    $controller = $this->getAuthorizeController($client);
    $response = $controller->content($node);
    $this->assertContains('You’ve used 3 of your 3 allowed downloads for the year.', $response->getContent());
    $this->assertContains('Download Paper Anyway', $response->getContent());

    $client = $this->getMockClient(1, 3, 1);
    $controller = $this->getAuthorizeController($client);
    $response = $controller->content($node);
    $this->assertContains('You’ve used 1 of your 3 allowed downloads for the year.', $response->getContent());
    $this->assertContains('Download Paper Anyway', $response->getContent());

    $client = $this->getMockClient(1, 2, 1);
    $controller = $this->getAuthorizeController($client);
    $response = $controller->content($node);
    $this->assertContains('You’ve used 1 of your 2 allowed downloads for the year.', $response->getContent());

    $client = $this->getMockClient(0, 3, 3);
    $controller = $this->getAuthorizeController($client);
    $response = $controller->content($node);
    $this->assertNotContains('Download Paper Anyway', $response->getContent());
    $this->assertContains('<a href="http://example.org?id=w12345" class="btn btn--primary btn--black">Purchase Paper for $5</a>', $response->getContent());
    $this->assertContains('<a href="http://example.org?referer=http%3A//localhost/node/1" class="btn btn--primary btn--black">Have Access? Login to Account</a>', $response->getContent());
  }

  /**
   * Return a mocked client. Allow changing of some values to influence the
   * controllers response object.
   */
  protected function getMockClient(int $allow = 1, int $claims_max = 3, int $claims_used = 1) {
    $client = $this->getMockBuilder('\Drupal\mymodule\Client\AuthorizeClient')
      ->disableOriginalConstructor()
      ->getMock();
    $client->expects($this->any())
      ->method('request')
      ->with('w12345', FALSE)
      ->willReturn(
        [
          'allow' => $allow,
          'claims_max' => $claims_max,
          'claims_used' => $claims_used,
          'failed_reason' => NULL,
          'succeeded_reason' => NULL,
          'subscriber_id' => 12345,
          'subscriber_logo_url' => NULL,
          'subscriber_name' => "Test",
          'subscriber_type' => "SUBS",
        ]
      );

    return $client;
  }

  /**
   * Return a controller with a mocked client.
   */
  protected function getAuthorizeController($client) {
    return new AuthorizeController($client, $this->container->get('renderer'), $this->container->get('entity_type.manager'), $this->container->get('request_stack'), $this->container->get('logger.factory'));
  }

}

This seems like a valid approach and the cases are working, and executes much faster than browser tests. The mymodule_authtest contains a content type with a couple of field configuration files and example PDF file to use in this test.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.