Como obter ScopeConfigInterface através do gerenciador de objetos de testes de unidade no magento 2?

8

Eu estou tentando ler uma linha no meu teste de unidade de core_config_table no banco de dados magento 2. Eu sei que para realizar este trabalho, eu li este link . Eu tenho que usar:

\Magento\Framework\App\Config\ScopeConfigInterface

através:

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

Aqui está o meu 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);
    }
}

Posso obter todos os objetos que eu quiser usando testObject, \Magento\Framework\TestFramework\Unit\Helper\ObjectManagermas sempre que eu quiser\Magento\Framework\App\Config\ScopeConfigInterface

Erro fatal: Não é possível instanciar a interface Magento \ Framework \ App \ Config \ ScopeConf igInterface em C: \ xampp \ htdocs \ magento \ vendor \ magento \ framework \ TestFramework \ Un it \ Helper \ ObjectManager.php na linha 162

ali gh
fonte
mesmo problema aqui ....
Michel Gokan 01/01

Respostas:

12

Posso estar errado aqui, mas acho que, para testes de unidade, você não precisa recuperar valores do banco de dados. Você pode assumir que as implementações de \Magento\Framework\App\Config\ScopeConfigInterfacesão testadas e funcionam corretamente. Você só precisa testar seu método que usa a getValuepartir do ScopeConfigInterface.
Por exemplo, se você tiver um método como este:

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

você precisa testar apenas esse método e não se o valor do banco de dados é o que você precisa.
e você pode testar isso assim:

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

Dependendo do número de dependências que precisam ser injetadas no construtor, talvez você nem precise usar o ObjectManager de teste de unidade, mas pode simplesmente instanciar diretamente a classe em teste usando new.

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

Isso é mais simples e, como tal, preferível para testes de unidade. O único motivo para usar o gerenciador de objetos de teste de unidade é se um grande número de dependências torna a zombaria de cada uma delas manualmente muito complicada.

Marius
fonte
obrigado pela sua ótima resposta. Considere que eu quero escrever um teste cujo objetivo seja que, quando uma configuração principal for "True", os dados de alguns produtos sejam substituídos por X e quando for "False", em seguida, os dados de alguns produtos sejam substituídos por Y. Se eu precisar escrever um Simulado para testar essa funcionalidade no meu módulo, então qual é o objetivo dos testes de unidade? Quero testar meu módulo real e real, não "uma farsa" de sua funcionalidade.
ali gh
neste caso, você faz 2 testes. um para quando o método getValueretorna true ->willReturn(true)e outro para quando getValueretorna false. ->willReturn(false). Dessa forma, você testa seu módulo real nos dois casos, não dependendo do que você possui no seu banco de dados.
Marius
11
@Marius está correto se você estiver escrevendo um teste de unidade, então você não deve falar diretamente com o banco de dados, mas sim em escopo no scopeConfigInterface e assumir que o estado de configuração do banco de dados está definido. Quando você deseja obter dados de o banco de dados que você está começando a mover para testes de integração, onde é possível invocar o banco de dados real para obter dados e executar asserções nele.
James Cowie 01/06
@Marius Eu fiz o que você mencionou, mas quando eu afirmar que sempre vai ter verdadeiro mesmo se $ dbValue não tem o valor real no banco de dados
ali gh
@aligh. Esse era o ponto. Leia o comentário acima de James Cowie. Ele é muito mais uma autoridade em testes de unidade (e todo o tipo de teste) do que eu sou ou jamais serei.
Marius
1

Eu acho que você precisa usar mock para isso, mas no seu caso, será necessária alguma refatoração do seu módulo, especialmente a necessidade de uma Configclasse relacionada ao seu módulo.

Você pode basear seu desenvolvimento no app/code/Magento/Braintree/Test/Unit/Gateway/Config/ConfigTest.phpque implementa algo como isto:

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 na Digital Pianism
fonte
Qual é o papel da função willReturn no método 'testGetCountrySpecificCardTypeConfig'?
ali gh 01/06