1

I'm running an error with the following test I wrote including some config. I don't know if my test is even properly written so any advice in improving that code is welcomed. Since my test is not finish yet, dont mind the self::assertTrue(TRUE);

Here is my Test :

namespace Drupal\mymodule\Tests\Service;

use Drupal\Component\Serialization\Json;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase;
use Drupal\mymodule\Service\MyClass;

/**
 * MyClass Test.
 *
 * @group mymodule
 */
class MyClassTest extends UnitTestCase {

  private $params;
  protected $configFactory;
  protected $loggerFactory;
  protected $container;
  protected $myClass;

  /**
   * Set Up.
   */
  public function setUp() {
    parent::setUp();
    $this->configFactory = $this
      ->getConfigFactoryStub([
        'mymodule.settings' => [
          'api' => [
            'hostname' => 'https://example.com',
            'periodbars_uri' => '/api/v2.0/articles',
            'api_key' => 'aaabbbcccdddeeefffzzz',
          ],
        ],
      ]);
    $this->container = new ContainerBuilder();
    $this->container
      ->set('config.factory', $this->configFactory);
    \Drupal::setContainer($this->container);
    $this->loggerFactory = $this
      ->getMockBuilder('Drupal\Core\Logger\LoggerChannelFactoryInterface')
      ->disableOriginalConstructor()
      ->getMock();
    $this->params = [
      'criteria' => [
        'id' => '1',
      ],
    ];
    $this->myClass = new MyClass($this->configFactory, $this->loggerFactory);
  }

  /**
   * Test API Accor Fetcher.
   */
  public function testMyClass() {
    $params = Json::encode($this->params);

    $url = 'https://example.com/api/v2.0/articles';

    $this->myClass->myClassRequest($url, $params, 'FR');

    self::assertTrue(TRUE);
  }

}

And here is the class I test :

namespace Drupal\mymodule\Service;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Pool;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use Drupal\Core\Url;

/**
 * Provides all the functions to call MyClass Webservices.
 */
class MyClass {

  protected $configFactory;
  protected $loggerFactory;

  /**
   * AccorWebService constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config Factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   Logger Factory.
   */
  public function __construct(ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory) {
    $this->configFactory = $config_factory;
    $this->loggerFactory = $logger_factory;
  }

  /**
   * The Guzzle Request.
   *
   * @param string $url
   *   The url of the webservice to call.
   * @param string $params
   *   The params to be sent to the webservice formatted in JSON.
   * @param string $langcode
   *   The langcode to call the webservice.
   *
   * @return \Psr\Http\Message\StreamInterface|null
   *   The response from the webservice.
   */
  public function myClassRequest($url, $params, $langcode = 'FR') {

    $api_key = $this->configFactory->get('mymodule.settings')->get('api.api_key');
    $headers = [
      'apikey' => $api_key,
      'Content-Type' => 'application/json',
      'Accept-Language' => $langcode,
    ];

    $client = new Client();

    $response = NULL;
    try {
      $request = $client->request('POST', $url, [
        'headers' => $headers,
        'body' => $params,
      ]);
      $response = $request->getBody();
    }
    catch (ClientException $e) {
      $this->loggerFactory->get('mymodule')
        ->error($e->getMessage());
    }
    catch (ServerException $se) {
      $this->loggerFactory->get('mymodule')
        ->error($se->getMessage());
    }

    return $response;
  }

When I run the Test in PHPStorm, I get Call to a member function get() on null on the line where the code is : $api_key = $this->configFactory->get('mymodule.settings')->get('api.api_key');

0

I know it's been quite some time, but did you ever figure out how to appropriately fix this?

I had exactly the same issue over the last couple of days, and I did kind of work out why and a way to get around it.. Though depending on what config data you need to return I'm not sure my "workaround" would be suitable.

In an attempt to explain what I've found and how I prevented the Call to a member function get() on null error - the $api_key = $this->configFactory->get('mymodule.settings')->get('api.api_key'); isn't actually being overridden by the configFactory mock because it's part of the class function you're testing and for some reason isn't overridden by your mock return call. Adapting my workaround to your implementation:

In your class

  1. Move $api_key = $this->configFactory->get('mymodule.settings')->get('api.api_key'); to it's own function (example name getApiConfig)
  2. Call it in the myClassRequest function with $api_key = getApiConfig();

In your test

  1. Stub getApiConfig in your class mock
  2. Return the required value(s)/array/object as required from a class stub return

Unfortunately I can't provide an update to your provided code as I'm unsure how my "workaround" impacts your implementation of new MyClass but hopefully this helps you, or others who come across this!

  • Thank you for your comment and it's not too late :-), I never had the chance to find a solution. I'll try yours ASAP and let you know if I manage to make it work. – pbonnefoi Sep 2 at 11:03
  • Hopefully it helps! I literally searched for hours to find even a remote reference, and even then it was trial and error that found me this. Good luck! – wonderlands-nightmare Sep 3 at 4:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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