测试构造函数太多了吗?

时间:2012-11-23 03:14:00

标签: php unit-testing phpunit software-quality

首先,我会说我来自Java世界(这很重要,真的)。

我已经编写了一段时间的PHP,我遇到的一个问题是由于缺少编译,有时可能在编译时很容易检测到错误(例如,给定的参数数量错误功能),可以默默传递。

通过添加单元测试,可以轻松检测到代码覆盖率增加。问题是,例如测试构造函数以检查传递的参数是否正确是否有意义?我不是指参数的数量,而是指这些参数的内容(例如,如果参数为null,某些对象应该启动异常以避免创建“脏”对象)。

问题是,我是否因多年的Java代码而受到污染?毕竟,增加代码覆盖率以“发现”错过的函数感觉就像(真正)原始的编译方式。

另外,我想说明我已经使用了开发环境(PHPStorm),我们也使用了像PHPCodeSniffer这样的工具。

有任何想法/建议吗?

3 个答案:

答案 0 :(得分:4)

这是一个很好的问题,可以在多个层面上得到解答:

  1. 语言特征
  2. 测试覆盖率
  3. CASE工具
  4. <强> 1。语言特征 正如您所指出的,PHP语言的特征与Java等强类型语言明显不同。这引发了一个严重的问题,即来自Java和C#等强类型语言的程序员可能不会意识到PHP行为的含义(例如你所描述的那些)。这引入了程序员错误的可能性(例如,程序员可能不太小心使用Java,因为他们知道编译器会捕获不正确的参数,但在PHP开发时可能不会应用适当的注意事项)。 因此,需要更好的程序员教育/监督来解决这个问题(例如内部公司编码标准,结对编程,代码审查)。它(正如你所指出的那样)提出了一个问题,即是否应该增加测试覆盖率以检查编译器会捕获的错误。

    <强> 2。测试覆盖率 测试覆盖范围的参数是特定于项目的。在现实世界中,测试覆盖率的水平主要取决于客户的容错能力(由系统中发生的错误的后果决定)。如果您正在开发在实时控制系统上运行的软件,那么显然您将测试更多。在您的问题中,您将PHP视为首选语言;这同样适用于关键系统基础架构中不断增加的基于Web的前端数量。另一方面,如果您正在为模型铁路俱乐部开发一个简单的网站,并且正在开发一个时事通讯应用程序,那么您的客户可能不关心构造函数中是否存在错误。

    第3。案例工具 最终,需要一种可以检测这些错误的CASE工具,例如缺少参数。如果那里没有合适的工具,为什么不创建自己的工具呢?大多数程序员都无法创建CASE工具,特别是如果您可以使用您的语言的开源解析引擎。如果你是开源倾向,这可能是一个很好的项目,或者你的公司可能会推出这样的解决方案。

    <强>结论 在你的情况下,是否测试构造函数基本上归结为一个问题:我的系统失败的后果是什么?如果在测试构造函数上花费额外资源以避免此类失败具有经济意义,那么您应该这样做。否则,可能会通过较少的测试来完成,例如结对编程或代码审查。

答案 1 :(得分:3)

如果设置了无效参数,您是否希望构造函数抛出异常?你希望明天,下周和明年的行为方式相同吗?然后你编写一个测试来验证它确实存在。

测试验证您的代码是否符合您的要求。失败的无效参数是代码行为,与计算销售税或显示用户的个人资料页面一样多。

答案 2 :(得分:1)

我们测试构造函数,参数的顺序,未提供的默认值,然后是一些实际设置。例如:

class UTIL_CATEGORY_SCOPE extends UTIL_DEPARTMENT_SCOPE
{
    function __construct($CategoryNo = NULL, $CategoryName = NULL)
    {
        parent::__construct();              // Do Not Pass fields to ensure that the array is checked when all fields are defined.
        $this->DeclareClassFields_();

        $this->CategoryName = $CategoryName;
        $this->CategoryNo   = $CategoryNo;
    }

    private function DeclareClassFields_()
    {
        $this->Fields['CategoryNo']             = new UTIL_ICAP_FIELD_PAIR_FIRST('CCL', 6, ML('Category'), 8);
        $this->Fields['CategoryName']           = new UTIL_ICAP_FIELD_PAIR_SECOND('CCL', 32, ML('Name'), 15, array(), array(), NULL, UTIL_ICAP_FIELD::EDIT_DENY, UTIL_ICAP_FIELD::UPDATE_DENY, 'DES');
    }
}

然后我们创建测试,不仅检查构造函数及其顺序,而且该类和继承没有改变。

public function testObjectCreation()
    {
        $CategoryInfo = new UTIL_CATEGORY_SCOPE();
        $this->assertInstanceOf('UTIL_CATEGORY_SCOPE', $CategoryInfo);
        $this->assertInstanceOf('UTIL_DEPARTMENT_SCOPE', $CategoryInfo);
        $this->assertInstanceOf('UTIL_DATA_STRUCTURE', $CategoryInfo);     // Inherited from UTIL_DEPARTMENT_SCOPE
    }

    public function testConstructFieldOrder()
    {
        $CategoryInfo = new UTIL_CATEGORY_SCOPE(1500, 'Category Name');
        $this->assertEquals(1500, $CategoryInfo->CategoryNo);
        $this->assertEquals('Category Name', $CategoryInfo->CategoryName);
    }

    public function testConstructDefaults()
    {
        $CategoryInfo = new UTIL_CATEGORY_SCOPE();
        $this->assertNull($CategoryInfo->CategoryNo);
        $this->assertNull($CategoryInfo->CategoryName);
    }

    public function testFieldsCreated()
    {
        $CategoryInfo = new UTIL_CATEGORY_SCOPE();
        $this->assertArrayHasKey('CategoryNo', $CategoryInfo->Fields);
        $this->assertArrayHasKey('CategoryName', $CategoryInfo->Fields);
        $this->assertArrayHasKey('DeptNo', $CategoryInfo->Fields);      // Inherited from Parent
        $this->assertArrayHasKey('DeptName', $CategoryInfo->Fields);    // Inherited from Parent
    }