2

I am attempting to write a unit test by extending UnitTestCase. Below is how my code works, but I need a way to create a test (or mock) configuration that can be used to satisfy the testing.

How can I accomplish this?

To keep question short i am only adding pertinent code. Current issue is that my test cases are failing because the configuration is not valid.

Error message:

Drupal\Core\DependencyInjection\ContainerNotInitializedException: \Drupal::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.

mymodule/src/plugin/mymodule_field/provider/MyClass.php

class MyClass extends ProviderPluginBase {
  /**
   * {@inheritdoc}
   */
  public static function someFunction($input) {
    // Get the config.
    $config = \Drupal::config('mymodule.settings');
    $test_value = $config->get('test');

    if (!empty($test_value)) {
      /* process $test value */
      return True;
    }
    elseif (empty($test_value)) {
      /* do something else */
      return false;
    }
  }
}

mymodule/test/src/Unit/MyModuleValueTest.php

class MyModuleValueTest extends UnitTestCase {
  public function testIsEmpty($value, $expected) {
    /* I am stuck here on how to get the config */
    $this->assertEquals($expected, MyClass::someFunction($value));
  }
}

1 Answer 1

2

You are missing a couple of basic ideas of unit testing. I try to show them to you:

What is a unit?

Unit is most cases (95%+) a single class. This unit has some dependencies, using them and adding some extra logic to the whole.

In a unit test you only want to test the logic you provide in your class, but you want to make the dependencies as black boxes. A change to the implementation of the dependencies should NEVER make any difference to your unit test. Only their interfaces what matters.

Clear Dependencies

One of the dependency injection main role is to make your class testable. By injecting all the dependencies through the constructor you not just giving a nice list what services you class is relying on, but also make it easy to test.

Static methods should not be harder to test than object methods but they have a big drawback: you can't handle calling another static method inside them. Here is a nice explanation:

Unit-Testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. Seams work through polymorphism, we override/implement class/interface and then wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to override the called method dependency.

About your case

Either you need to eliminate the dependency by providing the value you need via argument, or you will have to give up unit testing on this one. You still can write a kernel test tho. That will be of course slower, but you can also have a wider scope of functionality / integration to be tested.

3
  • I cannot give up on unit testing as the patch I deployed fails due to the error mentioned in the question. We need to provide a way to create a mock configuration so that when the method is called, it can test both the if and elseif Commented Mar 22, 2018 at 16:35
  • So don't use static call in a static function. Rather path the config service to it (but rather the the value you need from it). Why is my answer is not correct?
    – ssibal
    Commented Mar 22, 2018 at 19:32
  • after testing we have removed the static call and allowed it to be passed in. Commented Mar 26, 2018 at 18:28

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.