【问题标题】:How to unit-test an abstract class, when its constructor executes its abstract method(-s)?当其构造函数执行其抽象方法(-s)时,如何对抽象类进行单元测试?
【发布时间】:2013-12-24 16:06:04
【问题描述】:

我正在为这个Zend Framework 2 类编写PHPUnit 单元测试:

<?php
namespace MyNamespace\InputFilter;

use Zend\InputFilter\Input as ZendInput;
use Zend\InputFilter\Factory;
use Zend\InputFilter\InputInterface;
use MyNamespace\Exception\InvalidParameterException;

abstract class AbstractInput extends ZendInput
{
    final public function __construct()
    {
        // The constructor uses/executes the abstract method getInputSpecification().
        $this->init($this->getInputSpecification());
    }
    public function merge(InputInterface $input)
    {
        $mergedInput = parent::merge($input);
        $mergedInput->setFallbackValue($input->getFallbackValue());
        return $mergedInput;
    }
    public function isValid()
    {
        $this->injectNotEmptyValidator();
        $validator = $this->getValidatorChain();
        $value     = $this->getValue();
        $result    = $validator->isValid($value, $context);
        return $result;
    }
    protected function init($inputSpecification)
    {
        $factory = new Factory();
        $tempInput = $factory->createInput($inputSpecification);
        $this->merge($tempInput);
    }
    abstract protected function getInputSpecification();
    public function getFinalValue($param)
    {
        $finalValue = null;
        if (empty($param) || $this->getValue() === '') {
            if ($this->getFallbackValue() !== null) {
                $finalValue = $this->getFallbackValue();
            } else {
                throw new InvalidParameterException('The parameter ' . $this->name . ' must be set!');
            }
        } else {
            if ($this->isValid()) {
                $finalValue = $this->getValue();
            } else {
                throw new InvalidParameterException('The parameter ' . $this->name . ' is invalid!');
            }
        }
        return $finalValue;
    }
}

并对此有疑问。这段代码

// ...
class AbstractInputTest extends TestCase
{
    // ...
    public function setUp()
    {
        $stub = $this->getMockForAbstractClass('\MyNamespace\InputFilter\AbstractInput');
        $stub
            ->expects($this->any())
            ->method('getInputSpecification')
            ->will($this->returnValue(array())
        );
        // ...
    }
    // ...
}

导致错误:

$ phpunit SgtrTest/InputFilter/AbstractInputTest.php PHPUnit 3.7.21 by Sebastian Bergmann。

从 /path/to/project/tests/phpunit.xml 读取配置

E...

时间:1 秒,内存:7,00Mb

有 1 个错误:

1) SgtrTest\InputFilter\AbstractInputTest::testMerge Zend\InputFilter\Exception\InvalidArgumentException: Zend\InputFilter\Factory::createInput 需要一个数组或 Traversable; 收到“NULL”

/path/to/project/vendor/ZF2/library/Zend/InputFilter/Factory.php:98 /path/to/project/vendor/SGTR/library/MyNamespace/InputFilter/AbstractInput.php:72 /path/to/project/vendor/SGTR/library/MyNamespace/InputFilter/AbstractInput.php:31 /path/to/project/tests/SgtrTest/InputFilter/AbstractInputTest.php:20

失败!测试:4,断言:0,错误:1。

我不明白,为什么会抛出错误。但是如何用另一种方式解决这个问题?

【问题讨论】:

  • 对扩展你的抽象的具体类进行单元测试......并不是说它是一个具有抽象方法的类,而不是一个抽象类
  • 感谢您的评论。但是不应该对抽象类进行单元测试吗?好的,抽象类也包含具体方法——它们应该被测试——直接在类的测试类中,而不是在子类的测试类中。例如。 ZendTest\Cache\Storage\Adapter\AbstractAdapter

标签: php unit-testing zend-framework2 phpunit abstract-class


【解决方案1】:

在我的测试中,我创建了一个扩展抽象类的快速类,然后测试该类中的具体方法。

class TestAbstractInput extends AbstractInput
{
    ...
}

class AbstractInputTest extends TestCase
{
    // ...
    public function setUp()
    {
        $this->TestClassObject = new TestAbstractInput();
    }

    public function test_isValid()
    {
        $this->assertEquals(1, $this->TestClassObject->isValid);
    }
}

在此之后,您可以使用在测试中创建的 Abstract 类的 Mock 对象,或者像您所做的那样模拟 Abstract 类。

【讨论】:

  • 我认为,这是一个很好的解决方法。必须尝试一下。谢谢!
  • 这对你有用吗?如果是这样,您是否可以接受答案供其他人查看,或者我可以通过提供更多信息来提供帮助吗?
猜你喜欢
  • 2011-12-19
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多