简体   繁体   English

测试构造函数太多了吗?

[英]Is testing constructor too much?

Firstly, I will say that I come from the Java world (this is important, really). 首先,我会说我来自Java世界(这很重要,真的)。

I have been coding PHP for a while, one of the problems that I have encountered is that due to the lack of compilation, sometimes errors that could be easily detected at compilation time (for example, wrong number of parameters for a given function), can silently pass. 我已经编写了一段时间的PHP,我遇到的一个问题是由于缺少编译,有时可能在编译时很容易检测到错误(例如,给定函数的参数数量错误),可以默默地通过。

That could be easily detected as code coverage increases by adding unit tests. 通过添加单元测试,可以轻松检测到代码覆盖率增加。 The question is, does it make sense for example to tests constructors in order to check that the passed parameters are correct? 问题是,例如测试构造函数以检查传递的参数是否正确是否有意义? I do not mean only the number of parameters, but also the content of such parameters (for example, if a parameter is null, certain objects should launch an exception in order to avoid creating a "dirty" object). 我不是指参数的数量,而是指这些参数的内容(例如,如果参数为null,某些对象应该启动异常以避免创建“脏”对象)。

Question is, am I too contaminated by years of Java code? 问题是,我是否被多年的Java代码污染了? Because after all, increasing the code coverage to "discover" missued functions feels like a (really) primitive way of compiling. 因为毕竟,增加代码覆盖率以“发现”错过的函数感觉就像(真正)原始的编译方式。

Also, I would like to note that I already use a development environment (PHPStorm), we are also using tools like PHPCodeSniffer. 另外,我想说明我已经使用了开发环境(PHPStorm),我们也使用了像PHPCodeSniffer这样的工具。

Any ideas/suggestions? 有什么想法/建议吗?

This is a good question that can be answered on a number of levels: 这是一个很好的问题,可以在许多层面上得到解答:

  1. Language characteristics 语言特征
  2. Test coverage 测试范围
  3. CASE tools CASE工具

1. Language characteristics As you have pointed out the characteristics of the PHP language differ markedly from the more strongly-typed languages such as Java. 1.语言特征正如您所指出的,PHP语言的特征与Java等强类型语言明显不同。 This raises a serious issue where programmers coming from the more strongly-typed languages such as Java and C# may not be aware of the implications of PHP's behaviour (such as those you have described). 这引发了一个严重的问题,即来自Java和C#等强类型语言的程序员可能不会意识到PHP行为的含义(例如你所描述的那些)。 This introduces the possibility of mistakes on the part of the programmer (for example, a programmer who may have been less careful using Java because they know the compiler will catch incorrect parameters may not apply the appropriate care when developing in PHP). 这引入了程序员错误的可能性(例如,程序员可能不太小心使用Java,因为他们知道编译器会捕获不正确的参数,但在PHP开发时可能不会应用适当的注意事项)。 Consequently, better programmer education/supervision is needed to address this issue (such as in-house company coding standards, pair programming, code review). 因此,需要更好的程序员教育/监督来解决这个问题(例如内部公司编码标准,结对编程,代码审查)。 It also (as you have pointed out) raises the question of whether test coverage should be increased to check for such mistakes as would have been caught by a compiler. 它(正如你所指出的那样)提出了一个问题,即是否应该增加测试覆盖率以检查编译器会捕获的错误。

2. Test Coverage The argument for test coverage is very project-specific. 2.测试覆盖率测试覆盖率的参数是特定于项目的。 In the real world, the level of test coverage is primarily dictated by the error tolerance of the customer (which is dictated by the consequences of an error occuring in your system). 在现实世界中,测试覆盖水平主要取决于客户的容错能力(由系统中发生错误的后果决定)。 If you are developing software that is to run on a real-time control system, then obviously you will test more. 如果您正在开发在实时控制系统上运行的软件,那么显然您将测试更多。 In your question you identify PHP as the language of choice; 在您的问题中,您将PHP视为首选语言; this could apply equally to the ever-increasing number of web-enabled frontends for critical systems infrastructure. 这同样适用于关键系统基础架构中不断增加的基于Web的前端数量。 On the other side of the coin, if you are developing a simple website for a model railroad club and are just developing a newsletter app then your customer may not care about the possibility of a bug in the constructor. 另一方面,如果您正在为模型铁路俱乐部开发一个简单的网站,并且正在开发一个时事通讯应用程序,那么您的客户可能不会关心构造函数中存在错误的可能性。

3. CASE Tools Ultimately it would be desirable for a CASE tool to be available which can detect these errors, such as missing parameters. 3. CASE工具最终,CASE工具可用于检测这些错误,例如缺少参数。 If there are no suitable tools out there, why not create one of your own. 如果那里没有合适的工具,为什么不创建自己的工具呢? The creation of a CASE tool is not out of reach of most programmers, particularly if you can hook into an open-source parsing engine for your language. 大多数程序员都无法创建CASE工具,特别是如果您可以使用您的语言的开源解析引擎。 If you are open-source inclined this may be a good project to kick start, or perhaps your company could market such a solution. 如果你是开源倾向,这可能是一个很好的项目,或者你的公司可能推销这样的解决方案。

Conclusion In your case whether or not to test the constructors basically comes down to the question: what will the consequences of a failure in my system be? 结论在你的情况下,是否测试构造函数基本上归结为一个问题:我的系统失败的后果是什么? If it makes financial sense to expend extra resources on testing your constructors in order to avoid such failures, then you should do so. 如果在测试构造函数上花费额外资源以避免此类失败具有经济意义,那么您应该这样做。 Otherwise it may be possible to get by with lesser testing such as pair programming or code reviews. 否则,可能会通过较少的测试来完成,例如结对编程或代码审查。

Do you want the constructor to throw an exception if invalid parameters set? 如果设置了无效参数,您是否希望构造函数抛出异常? Do you want it to behave that same way tomorrow and next week and next year? 你希望明天,下周和明年的行为方式相同吗? Then you write a test to verify that it does. 然后你编写一个测试来验证它确实存在。

Tests verify that your code behaves as you want it to. 测试验证您的代码是否按照您的意愿运行。 Failing on invalid parameters is code behavior just as much as calculating sales tax or displaying a user's profile page. 失败的无效参数是代码行为,与计算销售税或显示用户的个人资料页面一样多。

We test constructors, as well as the order of the parameters, the defaults when not provided, and then some actual settings. 我们测试构造函数,参数的顺序,未提供的默认值,然后是一些实际设置。 For instance: 例如:

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');
    }
}

We then create our tests to not only check the constructor and its order, but that class and inheritance has not changed. 然后我们创建我们的测试,不仅检查构造函数及其顺序,而且该类和继承没有改变。

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
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM