8

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

1

2 Answers 2

12

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.

5
  • thanks for your great answer. Consider I want to write a test which its purpose is that when a core config is "True" then some product's data should get replaced with X and when its "False" then some product's data should replaced with Y. If I need to write a mock to test this functionallity in my module, then what's the point of unit testing ? I want to test my actual and real module, not "a mock" of its functionality.
    – ali gh
    Jun 1, 2016 at 11:44
  • in this case you make 2 tests. one for when the method getValue returns true ->willReturn(true) and one for when getValue returns false. ->willReturn(false). This way you test your actual module in both cases, not depending on what you have in your db.
    – Marius
    Jun 1, 2016 at 12:01
  • 1
    @Marius is correct if you are writing a unit test then you should not be talking to the database directly but instead you should be mocking the on the scopeConfigInterface and assume that the database config state is set, When you start to want to get data from the database you are starting to move into integration tests where you can then invoke the actual database to get data and perform assertions on it. Jun 1, 2016 at 12:09
  • @Marius I have done what you mentioned but when I assert I will always get true even if $dbValue has not the actual value in database
    – ali gh
    Jun 1, 2016 at 12:12
  • @aligh. That was the point. Read the comment above from James Cowie. He's far more an authority in unit testing (and all kind of testing) than I am or will ever be.
    – Marius
    Jun 1, 2016 at 12:15
1

I reckon you need to use mock for this but in your case it will require some refactoring of your module, especially the need of a Config class related to your module.

You can base your development on the app/code/Magento/Braintree/Test/Unit/Gateway/Config/ConfigTest.php which implements something like this:

namespace Magento\Braintree\Test\Unit\Gateway\Config;

use Magento\Braintree\Gateway\Config\Config;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;

/**
 * Class ConfigTest
 */
class ConfigTest extends \PHPUnit_Framework_TestCase
{
    const METHOD_CODE = 'braintree';

    /**
     * @var Config
     */
    private $model;

    /**
     * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
     */
    private $scopeConfigMock;

    protected function setUp()
    {
        $this->scopeConfigMock = $this->getMock(ScopeConfigInterface::class);

        $this->model = new Config($this->scopeConfigMock, self::METHOD_CODE);
    }

    /**
     * @param string $value
     * @param array $expected
     * @dataProvider getCountrySpecificCardTypeConfigDataProvider
     */
    public function testGetCountrySpecificCardTypeConfig($value, $expected)
    {
        $this->scopeConfigMock->expects(static::once())
            ->method('getValue')
            ->with($this->getPath(Config::KEY_COUNTRY_CREDIT_CARD), ScopeInterface::SCOPE_STORE, null)
            ->willReturn($value);

        static::assertEquals(
            $expected,
            $this->model->getCountrySpecificCardTypeConfig()
        );
    }

    /* skipped code */
}
1
  • What is the role of willReturn function in 'testGetCountrySpecificCardTypeConfig' method ?
    – ali gh
    Jun 1, 2016 at 11:27

Your Answer

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

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