Come ottenere ScopeConfigInterface tramite il gestore oggetti dei test unitari in Magento 2?


8

Sto cercando di leggere una riga nel mio test unitario da core_config_table nel database magento 2. So che per realizzare questo lavoro come ho letto questo link . Devo usare:

\Magento\Framework\App\Config\ScopeConfigInterface

attraverso:

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

Ecco il mio codice:

    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 ottenere tutti gli oggetti che voglio usando testObject \Magento\Framework\TestFramework\Unit\Helper\ObjectManagerma ogni volta che voglio ottenere\Magento\Framework\App\Config\ScopeConfigInterface

Errore irreversibile: impossibile creare un'istanza dell'interfaccia Magento \ Framework \ App \ Config \ ScopeConf igInterface in C: \ xampp \ htdocs \ magento \ vendor \ magento \ framework \ TestFramework \ Un it \ Helper \ ObjectManager.php on line 162


stesso problema qui ....
Michel Gokan,

Risposte:


12

Potrei sbagliarmi qui, ma penso che per i test unitari non sia necessario recuperare i valori dal database. Si può presumere che le implementazioni di \Magento\Framework\App\Config\ScopeConfigInterfacesiano state testate e funzionino correttamente. Devi solo testare il tuo metodo che utilizza getValuedal ScopeConfigInterface.
Ad esempio, se hai un metodo come questo:

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

devi testare solo questo metodo e non se il valore dal db è quello che ti serve.
e puoi provarlo in questo modo:

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

A seconda del numero di dipendenze che devono essere iniettate nel costruttore, potrebbe non essere necessario utilizzare l'ObjectManager di unit test, ma è possibile semplicemente creare un'istanza della classe sotto test direttamente utilizzando new.

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

Questo è più semplice e come tale preferibile per i test unitari. L'unico motivo per utilizzare il gestore oggetti unit test è se un gran numero di dipendenze rende il deridere manualmente ciascuna di esse in modo ingombrante.


grazie per l'ottima risposta. Considera di voler scrivere un test il cui scopo è che quando una configurazione di base è "Vero", i dati di alcuni prodotti dovrebbero essere sostituiti con X e quando i suoi "Falsi" dovrebbero essere sostituiti con Y. Se ho bisogno di scrivere un finto di testare questa funzionalità nel mio modulo, qual è il punto di test dell'unità? Voglio testare il mio modulo reale e reale, non "un gioco" della sua funzionalità.
ali gh

in questo caso fai 2 test. uno per quando il metodo getValuerestituisce true ->willReturn(true)e uno per quando getValuerestituisce false. ->willReturn(false). In questo modo testerai il tuo modulo attuale in entrambi i casi, non dipendendo da quello che hai nel tuo db.
Marius

1
@Marius è corretto se si sta scrivendo un test unitario, quindi non si dovrebbe parlare direttamente con il database ma invece si dovrebbe prendere in giro l'ambito scopeConfigInterface e presumere che lo stato di configurazione del database sia impostato, quando si inizia a voler ottenere dati da il database che si sta iniziando a passare ai test di integrazione in cui è quindi possibile richiamare il database effettivo per ottenere dati ed eseguire asserzioni su di esso.
James Cowie,

@Marius Ho fatto quello che hai detto, ma quando asserisco diventerò sempre vero anche se $ dbValue non ha il valore reale nel database
ali gh

@aligh. Questo era il punto. Leggi il commento sopra di James Cowie. È molto più un'autorità nei test unitari (e tutti i tipi di test) di quanto io sia o non sarò mai.
Marius

1

Suppongo che devi usare mock per questo, ma nel tuo caso richiederà un po 'di refactoring del tuo modulo, in particolare la necessità di una Configclasse relativa al tuo modulo.

Puoi basare il tuo sviluppo su ciò app/code/Magento/Braintree/Test/Unit/Gateway/Config/ConfigTest.phpche implementa qualcosa del genere:

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 */
}

Qual è il ruolo della funzione willReturn nel metodo 'testGetCountrySpecificCardTypeConfig'?
ali gh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.