Magento 2 – How to Get ScopeConfigInterface Through Object Manager in Unit Tests

dependency-injectionmagento2object-managerphpunitunit tests

I'm trying to read a row in my unit test from core_config_table in magento 2 database. I know that to accomplish this job as I have read this link. I have to use:

\Magento\Framework\App\Config\ScopeConfigInterface

through:

\Magento\Framework\TestFramework\Unit\Helper\ObjectManager

Here is my code:

    protected function setUp()
{
    $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
    $this->scopeConfig = $objectManager->getObject('\Magento\Framework\App\Config\ScopeConfigInterface');
}

public function testgetImageCDNConfigValue()
{
    $this->scopeConfig->getValue($this->path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
    if ($this->scopeConfig == null) {
        $this->assertFalse(true);
    } else {
        $this->assertTrue(true);
    }
}

I can get every object I want by using testObject \Magento\Framework\TestFramework\Unit\Helper\ObjectManager but whenever I want to get \Magento\Framework\App\Config\ScopeConfigInterface

Fatal error: Cannot instantiate interface
Magento\Framework\App\Config\ScopeConf igInterface in
C:\xampp\htdocs\magento\vendor\magento\framework\TestFramework\Un
it\Helper\ObjectManager.php on line 162

Best Answer

I may be wrong here, but I think for unit tests you don't have to retrieve values from the data base. You can assume that the implementations of \Magento\Framework\App\Config\ScopeConfigInterface are tested and work properly. You only have to test your method that uses getValue from the ScopeConfigInterface.
For example, if you have a method like this:

public function getSomeConfigValue()
{
    return $this->scopeConfig->getValue('some/path/here', ScopeInterface::SCOPE_STORE)
}

you need to test that method only and not if the value from the db is what you need.
and you can test that like this:

public function testGetSomeConfigValue()
{
    $dbValue = 'dummy_value_here';
    $scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
            ->disableOriginalConstructor()
            ->getMock();
    $scopeConfigMock->method('getValue')
            ->willReturn($dbValue);
    $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
    $myClass = $objectManager->getObject(
        \Your\Class\Name\Here::class,
        [
             'scopeConfig' => $scopeConfigMock,
             ..., //your other mocked dependencies here
        ]
    );

    $this->assertEquals($dbValue, $myClass->getSomeConfigValue());
}

Depending on the number of dependencies that have to be injected into the constructor, you might not even have to use the unit test ObjectManager, but can simply instantiate the class under test directly using new.

$myClass = new \Your\Class\Name\Here($scopeConfigMock);

This is simpler and as such preferable for unit tests. The only reason to use the unit test object manager is if a large number of dependencies makes mocking each one manually too cumbersome.

Related Topic