【问题标题】:Mocking class instantiated in other class in Magento在 Magento 的其他类中实例化的模拟类
【发布时间】:2018-07-30 02:36:06
【问题描述】:

我正在尝试了解有关测试的更多信息,但不幸的是我必须在 Magento 1.9 中进行。* :)

考虑以下代码(GDPR 相关)...

class Vendor_Module_Helper_Data 
{
    public function __construct()
    {
        $this->config = Mage::helper('vendor_module/config');
    }

    public function anonymizeEmail(Mage_Customer_Model_Customer $customer)
    {
        return preg_replace_callback('#{([a-z_]*)}#', function ($matches) use ($customer) {
            return strtolower($customer->getData($matches[1]));
        }, $this->config->getEmailFormat());
    }
}

class Vendor_Module_Helper_Config 
{
    public function getEmailFormat()
    {
        return Mage::getStoreConfig('vendor_module/email/format));
    }
}

我正在编写一个测试,断言给客户的电子邮件格式正确,如下所示:

public function it_anonymizes_customer_email()
{
    $customer = Mage::getModel('customer/customer')
                    ->setEntityId(1)
                    ->setFirstname('Customer')
                    ->setLastname('Anonymous');

    $configStub = $this->createMock(Vendor_Module_Helper_Config::class);

    $configStub->method('getEmailFormat')
         ->willReturn('customer.{entity_id}@anonymo.us');

    $email = Mage::helper('vendor_module')->anonymizeEmail($customer);

    $this->assertEquals($email, 'customer.1@anonymo.us');
}

当然这不会按原样工作,但应该清楚我在这里尝试实现的目标......

我的问题是如何在不使用 Magento 所缺乏的 DI 的情况下使这项工作发挥最佳效果。

有没有办法模拟在另一个类的构造函数中实例化(保护)的类?这是最佳做法吗?

或者这是一个有效的解决方案:

class Vendor_Module_Helper_Data 
{
    public function __construct($args)
    {
        $this->config = isset($args['config'] ? $args['config'] : Mage::helper('vendor_module/config');
    }
}

然后在测试中:

$email = Mage::helper('vendor_module', ['config' => $configStub])->anonymizeEmail($customer);

我必须将类从 Helper 更改为 Model,因为 helper 不接受构造函数参数(我认为)。

一些建议将不胜感激!

【问题讨论】:

    标签: dependency-injection mocking phpunit magento-1.9


    【解决方案1】:

    在你的情况下,我认为最好有:

    class Vendor_Module_Helper_Data 
    {
        public function getConfig()
        {
            return Mage::helper('vendor_module/config');
        }
    
        public function anonymizeEmail(Mage_Customer_Model_Customer $customer)
        {
            return preg_replace_callback('#{([a-z_]*)}#', function ($matches) use ($customer) {
                return strtolower($customer->getData($matches[1]));
            }, $this->getConfig()->getEmailFormat());
        }
    }
    

    在你的测试中:

    public function it_anonymizes_customer_email()
    {
        $customer = Mage::getModel('customer/customer')
                        ->setEntityId(1)
                        ->setFirstname('Customer')
                        ->setLastname('Anonymous');
    
        $configStub = $this->createMock(Vendor_Module_Helper_Config::class);
    
        $configStub->method('getEmailFormat')
             ->willReturn('customer.{entity_id}@anonymo.us');
    
        $helper = $this->createMock(Vendor_Module_Helper_Data::class, ['getConfig']);
        $email->expects($this->once())->method("getConfig")->willReturn($configStub);
    
        $this->assertEquals('customer.1@anonymo.us', $helper-> anonymizeEmail($customer));
    }
    

    因此,您正在创建一个方法 getConfig,然后对其进行模拟以返回您创建的另一个模拟。

    另一方面,对于 Magento 1.X 中的测试,我建议使用模块 EcomDev,它可以加快测试速度,并允许您设置 magento 特定的固定装置。它已经有一段时间没有维护了,但它工作得很好,它会帮助你更快地编写测试。

    【讨论】:

    • 一切都清楚了,tnx。我想我也可以添加一个 setConfig() 方法并以这种方式传递 $mock 。 DI 也可以使用 setter 方法,对吧?
    • 绝对是的!您可能还想查看 EcomDev,因为它允许 $this->replaceByMock() 这样的方法,这意味着如果您正在实例化,请在您的方法中说一个助手,只要它是一个 magento 助手,您就可以替换它。
    • 我查看了 EcomDev,但我们正在使用自定义构建的 Magento 设置,使用 magento-composer-installer 和许多其他 Composer 包。要求 EcomDev 给我们带来了很多冲突:/ 例如,他们的 PHPUnit 版本是 4.*。我们现在正在使用digitalpianism/testframework,可能比 EcomDev 简单得多,但它现在适合我们的需求,因为我们主要是在测试我们自己的业务逻辑。
    • 很公平,我会看看你提到的测试框架,可能对我们有用!祝你测试顺利!
    猜你喜欢
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 2022-08-22
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多