1

I wrote a prepareDataSource function and unit test for that function as below. When I run test function it throw error: Error : Call to a member function loadByCode() on null Please help me how to fix it?

prepareDataSource function as below:

namespace MyApp\SaleReports\Ui\Component\Listing\Columns\CountryReport;

class CountryName extends \MyApp\SaleReports\Ui\Component\Listing\Columns\BaseColumn
{
    /**
     * Prepare Data Source
     *
     * @param array $dataSource
     * @return array
     */
    public function prepareDataSource(array $dataSource)
    {
        if (isset($dataSource['data']['items'])) {
            $fieldName = $this->getData('name');
            foreach ($dataSource['data']['items'] as & $item) {
                $country_id = $item['country_id'];
                $country = $this->_countryFactory->create()->**loadByCode**($country_id);
                $item[$fieldName] = $country->getName();
            }
        }

        return $dataSource;
    }
}

So I write unit test for this function as below:

<?php


namespace MyApp\SaleReports\Test\Unit\Ui\Component\Listing\Comlumns\CountryReport;

use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use MyApp\SaleReports\Ui\Component\Listing\Columns\CountryReport\CountryName;
class CountryNameTest extends \PHPUnit\Framework\TestCase
{
    protected $_model;
    protected $_country;

    public function setUp()
    {
        $objectManager = new ObjectManager($this);
        $contextMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContextInterface::class)
            ->getMockForAbstractClass();
        $processor = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\Processor::class)
            ->disableOriginalConstructor()
            ->getMock();
        $contextMock->expects($this->never())
            ->method('getProcessor')
            ->willReturn($processor);
        $this->_country = $this->getMockBuilder(\Magento\Directory\Model\Country::class)
            ->disableOriginalConstructor()
            ->getMock();
        $this->_model = $objectManager->getObject(
            CountryName::class,
            [
                '_country' => $this->_country,
                'context' => $contextMock
            ]
        );
    }

    public function testPrepareDataSource()
    {
        $country_id = 'US';
        $itemName = "itemName";
        $oldItemValue = "oldItemValue";
        $expectDeliveryName = "United States";

        $dataSource = [
            'data' => [
                'items' => [
                    [
                        "country_id" => $country_id,
                        $itemName => $oldItemValue
                    ]
                ]
            ]
        ];



        $this->_model->setData('name', $itemName);
        $dataSource = $this->_model->prepareDataSource($dataSource);
        $this->assertEquals($expectDeliveryName, $dataSource['data']['items'][0][$itemName]);
    }
}

The BaseColumn class as below:

<?php


namespace MyApp\SaleReports\Ui\Component\Listing\Columns;

use Magento\Framework\View\Element\UiComponentFactory;
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Directory\Model\CountryFactory;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Directory\Model\CurrencyFactory;

class BaseColumn extends \Magento\Ui\Component\Listing\Columns\Column
{

    /**
     * Column name
     */
    const NAME = 'name';
    private $_report;
    /**
     * @var StoreManagerInterface
     */
    private $_storeManager;

    /**
     * @var CurrencyFactory
     */
    private $_currency;
    protected $_priceCurrency;
    protected $_countryFactory;

    protected $_storeResolver;

    public function __construct(
        ContextInterface $context,
        UiComponentFactory $uiComponentFactory,
        \MyApp\SaleReports\Model\Report $report,
        PriceCurrencyInterface $priceCurrency,
        CountryFactory $countryFactory,
        StoreManagerInterface $storeManager,
        CurrencyFactory $currencyFactory,
        \Magento\Store\Model\StoreResolver $storeResolver,
        array $components = [],
        array $data = []
    ) {
        parent::__construct($context, $uiComponentFactory, $components, $data);
        $this->_report = $report;
        $this->_priceCurrency = $priceCurrency;
        $this->_countryFactory = $countryFactory;
        $this->_storeManager = $storeManager;
        $this->_currency = $currencyFactory->create();
        $this->_storeResolver = $storeResolver;
    }

    /**
     * @return StoreInterface
     * @throws NoSuchEntityException
     */
    protected function getStore()
    {
        $currentStore = $this->_storeResolver->getCurrentStoreId();
        return $this->_storeManager->getStore($currentStore);
    }

    /**
     * Convert money by currency
     * @param $money_value
     * @return float
     * @throws NoSuchEntityException
     */
    protected function convertMoney($money_value)
    {
        $currencyCode = $this->getStore()->getCurrentCurrencyCode();
        return $this->_priceCurrency->convert($money_value, $this->getStore(), $currencyCode);
    }

    protected function getCurrency($currencyCode)
    {
        return $this->_currency->load($currencyCode);
    }

    /**
     * Get store base currency code
     *
     * @return string
     */
    public function getBaseCurrencyCode()
    {
        return $this->_storeManager->getStore()->getBaseCurrencyCode();
    }
}

Thank you so much, BienHV

3
  • Can you add method __contructor to your class?
    – Toan Tam
    Commented Jun 17, 2020 at 2:17
  • I write contructor on \MyApp\SaleReports\Ui\Component\Listing\Columns\BaseColumn. The CountryName class extends BaseColumn. Commented Jun 17, 2020 at 2:43
  • To fix the issue, you need to write the logic for mock object $this->_countryFactory to return "United States" if the passed-in argument is "US"
    – Toan Tam
    Commented Jun 17, 2020 at 3:15

1 Answer 1

1

Most (as far as I can tell) mocks do not return anything. If you call a method on a mock, it will return null. These errors usually turns up when method calls are chained: $this->_countryFactory->create()->loadByCode($country_id). Basically the call to create of the _countryFactory mock returns null; you can't call loadByCode on null.

The process is to mock the factory's create method to return something. Sample untested code:

$countryFactoryMock = $this->createMock(\Magento\Directory\Model\CountryFactory:class);
$country = $objectManager->getObject(Country:class, []);
$countryFactoryMock->method('create')->willReturn($country);

Also, I didn't look at the country model, but I believe loadByCode calls the database; more mocking may be necessary.

Your Answer

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

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