PHPUnit和抽象类:如何测试接受参数的具体构造函数和其他具体方法

6

我有一个非常简单的类,就像下面这个:

abstract class Person
{
    private $id;
    private $createdOn;

    // ... More private properties

    protected $unfound = array();

构造函数对传递的数组$data进行foreach循环,并使用正确的方法将值分配给属性。 如果该方法不存在,则将键添加到受保护的数组中以跟踪它(我称其为$unfound,只是为了独特!)。
    public function __construct($data)
    {
        foreach ($data as $field => $value)
        {
            $method = 'set' . ucfirst($field);

            if (method_exists($this, $method))
            {
                $this->$method($value);
            }
            else
            {
                $this->unfound[] = $field;
            }
        }
    }

设置属性值的方法列表
    public function setId($id) {
        $this->id = $id;
    }

    public function setCreatedOn($createdOn) {
        $this->createdOn = $createdOn;
    }

以下是获取这些分配值的方法列表:

    public function getId() {
        return $this->id;
    }

    public function getCreatedOn() {
        return $this->createdOn;
    }
} // END of the class

如您所见,该类并不执行任何复杂的任务:它接受一个类似于数组的参数。
array(
    'id' => 4,
    'createdOn' => '2015-01-07 20:50:00',
    'unknownVar' => 'mah'
    // ... Other properties to set
    );

所以这个类循环遍历数组并使用键调用正确的方法来设置值。我认为这没什么复杂的。

更复杂的是测试它。

由于它是一个抽象类,我不能直接实例化它,而是必须模拟它。

我的问题是我不能将正确的参数传递给构造函数来测试是否正确地分配了值。

我尝试使用类似以下的内容:

public function testPerson()
{
   $abstractClass = '\My\Namespace\Person';

    $testData = array(
        'id' => 1,
        'createdOn' => '2015-01-07 19:52:00',
        'unfound' => 'Inexistent method'
        );

   $methods = array(
      'getId',
      'setId'
      );

    $mock = $this->getMockBuilder($abstractClass)
        ->setConstructorArgs(array($testData))
        ->setMethods($methods)
        ->getMockForAbstractClass();

    $this->assertEquals($testData['id'], $mock->getId());
}

在testPerson()函数中,$methods变量不包含我需要的所有方法,但是为了测试这个测试(请原谅我玩文字游戏!:)),我认为它们已经足够了。

但是PHPUnit告诉我:

Failed asserting that null matches expected 1.

似乎构造函数没有被调用,尽管代码覆盖率告诉我方法被调用了。
有人可以帮助我理解正在发生的事情以及如何测试这个类吗?
谢谢!

不要测试抽象类!测试那些扩展这些抽象类的具体类。 - Mark Baker
是的,好的,我知道规则。但我必须测试它。此外,这对我来说现在是一个挑战!我必须理解为什么! - Aerendir
好的,我来重新表述一下......你__无法__测试一个抽象类,因为(根据定义)它无法被实例化。你只能测试继承它的具体类。 - Mark Baker
1
嗨,抱歉打扰一下,但是也有一种测试抽象类的方法:getMockForAbstractClass()。我认为这是可能的(而且在更简单的类中我已经做过了)。 - Aerendir
1
也许https://dev59.com/NnVC5IYBdhLWcg3wxEJ1可以帮助。 - Mark Baker
显示剩余2条评论
1个回答

3
解决方案非常简单:删除$methods变量和调用setMethods($methods)即可解决问题!
事实上,调用setMethods()会“存根”那些方法,如果没有设置正确的固定值,这些方法将被设置为null(即我从测试结果中得到的值)。
我测试的方法被存根了,而其他方法没有被存根。
所以,print_r($mock)显示其他值已经被正确设置。
如此简单却难以找到!感谢你让我思考,因此我解决了这个问题并提出了这个问题!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接