¿Cómo obtener ScopeConfigInterface a través del administrador de objetos de pruebas unitarias en magento 2?

8

Estoy tratando de leer una fila en mi prueba unitaria de core_config_table en la base de datos magento 2. Sé que para lograr este trabajo, he leído este enlace . Tengo que usar:

\Magento\Framework\App\Config\ScopeConfigInterface

mediante:

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

Aquí está mi código:

    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);
    }
}

Puedo obtener todos los objetos que quiero usando testObject, \Magento\Framework\TestFramework\Unit\Helper\ObjectManagerpero cada vez que quiero obtener\Magento\Framework\App\Config\ScopeConfigInterface

Error grave: no se puede crear una instancia de la interfaz Magento \ Framework \ App \ Config \ ScopeConf igInterface en C: \ xampp \ htdocs \ magento \ vendor \ magento \ framework \ TestFramework \ Un it \ Helper \ ObjectManager.php en la línea 162

Ali GH
fuente
mismo problema aquí ...
Michel Gokan

Respuestas:

12

Puede que me equivoque aquí, pero creo que para las pruebas unitarias no tiene que recuperar valores de la base de datos. Puede suponer que las implementaciones de \Magento\Framework\App\Config\ScopeConfigInterfacese prueban y funcionan correctamente. Solo tiene que probar su método que utiliza getValuedesde ScopeConfigInterface.
Por ejemplo, si tiene un método como este:

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

solo necesita probar ese método y no si el valor de la base de datos es lo que necesita.
y puedes probar eso así:

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());
}

Dependiendo de la cantidad de dependencias que se deben inyectar en el constructor, es posible que ni siquiera tenga que usar el ObjectManager de prueba de unidad, sino que simplemente puede instanciar la clase bajo prueba directamente usando new.

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

Esto es más simple y, como tal, preferible para pruebas unitarias. La única razón para usar el administrador de objetos de prueba unitaria es si una gran cantidad de dependencias hace que burlarse de cada una sea demasiado engorroso.

Marius
fuente
Gracias por tu gran respuesta. Considere que quiero escribir una prueba cuyo propósito es que cuando una configuración central es "Verdadera", los datos de algunos productos deben reemplazarse por X y cuando es "Falso", los datos de algunos productos deben reemplazarse por Y. Si necesito escribir un simulacro para probar esta funcionalidad en mi módulo, entonces, ¿cuál es el punto de las pruebas unitarias? Quiero probar mi módulo real y real, no "un simulacro" de su funcionalidad.
Ali Gh
en este caso haces 2 pruebas. uno para cuando el método getValuedevuelve verdadero ->willReturn(true)y otro para cuando getValuedevuelve falso. ->willReturn(false). De esta manera, prueba su módulo real en ambos casos, sin depender de lo que tenga en su base de datos.
Marius
1
@Marius es correcto si está escribiendo una prueba unitaria, entonces no debería estar hablando directamente con la base de datos, sino que debería estar burlándose de en el alcanceConfigInterface y asumir que el estado de configuración de la base de datos está configurado, cuando comienza a querer obtener datos de la base de datos que está comenzando a pasar a las pruebas de integración donde puede invocar la base de datos real para obtener datos y realizar aserciones sobre ella.
James Cowie
@Marius que haya hecho lo que usted ha mencionado, pero cuando aseguro que siempre obtendrá cierto incluso si $ dbValue no tiene el valor real de la base de datos
ali gh
@aligh. Ese era el punto. Lea el comentario anterior de James Cowie. Es mucho más una autoridad en pruebas unitarias (y todo tipo de pruebas) de lo que soy o seré.
Marius
1

Creo que debe usar simulacro para esto, pero en su caso requerirá una refactorización de su módulo, especialmente la necesidad de una Configclase relacionada con su módulo.

Puede basar su desarrollo en lo app/code/Magento/Braintree/Test/Unit/Gateway/Config/ConfigTest.phpque implementa algo como esto:

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 */
}
Raphael en Digital Pianism
fuente
¿Cuál es el papel de la función willReturn en el método 'testGetCountrySpecificCardTypeConfig'?
Ali Gh