8

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

我一直在编写 PHP 代码,我遇到的一个问题是由于缺乏编译,有时在编译时很容易检测到错误(例如,给定函数的参数数量错误),可以默默地过去。

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

问题是,我是否被多年的 Java 代码污染了?因为毕竟,增加代码覆盖率以“发现”被误用的函数感觉就像一种(真正)原始的编译方式。

另外,我想指出我已经使用了一个开发环境(PHPStorm),我们也在使用像 PHPCodeSniffer 这样的工具。

有什么想法/建议吗?

4

3 回答 3

5

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

  1. 语言特点
  2. 测试覆盖率
  3. 案例工具

一、语言特点 正如您所指出的,PHP 语言的特性与 Java 等强类型语言明显不同。这引发了一个严重的问题,即来自 Java 和 C# 等强类型语言的程序员可能不知道 PHP 行为的含义(例如您所描述的那些)。这引入了程序员出错的可能性(例如,一个程序员在使用 Java 时可能不太小心,因为他们知道编译器会捕获不正确的参数,但他们在使用 PHP 开发时可能没有采取适当的谨慎措施)。因此,需要更好的程序员教育/监督来解决这个问题(例如内部公司编码标准、结对编程、代码审查)。

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

3. CASE 工具 最终希望有一个可用的 CASE 工具来检测这些错误,例如缺少参数。如果没有合适的工具,为什么不创建自己的工具。CASE 工具的创建对于大多数程序员来说并非遥不可及,特别是如果您可以连接到您的语言的开源解析引擎。如果您倾向于开源,这可能是一个很好的启动项目,或者您的公司可能会推销这样的解决方案。

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

于 2012-11-23T03:51:32.870 回答
3

如果设置了无效参数,您是否希望构造函数抛出异常?你希望它明天、下周和明年都以同样的方式表现吗?然后你写一个测试来验证它确实如此。

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

于 2012-11-23T03:46:48.430 回答
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
    }
于 2012-11-23T14:43:37.647 回答