我应该为任何可能的参数值编写单独的方法

时间:2013-10-22 19:18:07

标签: unit-testing phpunit

我对单元测试概念非常陌生,我坚持写第一篇。

我有一个标准化ID值的方法。它应返回任何正数的传递值(即使它是带有数字的字符串)和任何其他传递值的零(0)。

function normalizeId($val) {
    // if $val is good positive number return $val;
    // else return 0;
}

我想为这个函数编写一个单元测试,并断言任何可能的参数。例如: 5, -5, 0, "5", "-5", 3.14, "fff", new StdClass()等。

我应该在我的TestCase类中为任何这种情况编写一个方法,还是在一个单独的行上有一个所有条件的方法? 即。

public function testNormalizeId() {
    $this->assertEquals(5, MyClass::normalizeId(5));
    $this->assertEquals(0, MyClass::normalizeId(-5));
    $this->assertEquals(0, MyClass::normalizeId("fff"));
}

public function testNormalizeId_IfPositiveInt_GetPositiveInt() {
    $this->assertEquals(5, MyClass::normalizeId(5));
}
public function testNormalizeId_IfNegativeInt_GetZeroInt() {
   $this->assertEquals(0, MyClass::normalizeId(-5));
}
public function testNormalizeId_IfNotIntAsString_GetZeroInt() {
    $this->assertEquals(0, MyClass::normalizeId("fff"));
}

最佳做法怎么样?我听说第二种选择是好的但是我担心很多可能的参数值的方法。它可以是正数,负数,零,内部带正数的字符串,内部带负数的字符串,内部带浮点字符串等等。

修改

或许是第三种方法provider

public function testNormalizeIdProvider()
{
    return array(
        array(5, 5),
        array(-5, 0),
        array(0, 0),
        array(3.14, 0),
        array(-3.14, 0),
        array("5", 5),
        array("-5", 0),
        array("0", 0),
        array("3.14", 0),
        array("-3.14", 0),
        array("fff", 0),
        array("-fff", 0),
        array(true, 0),
        array(array(), 0),
        array(new stdClass(), 0),
    );
}

/**
 * @dataProvider testNormalizeIdProvider
 */
public function testNormalizeId($provided, $expected)
{
    $this->assertEquals($expected, MyObject::normalizeId($provided));
}

2 个答案:

答案 0 :(得分:2)

我对PHP以及你可以在其中使用的单元测试框架知之甚少,但在单元测试的一般领域中,出于这些原因,我建议采用第二种方法

  • 为特定类型的输入提供特定测试用例失败,而不是必须遍历实际的Assert失败消息以确定哪一个失败。

  • 如果您决定需要使用多个输入对特定类型的转换执行测试(例如,如果您决定使用包含1,000个随机字符串并且需要的文本文件),则可以更轻松地对这些测试进行参数化将它们加载到测试驱动程序中并运行测试用例,以便稍后通过功能或验收测试转换每个条目的字符串。

  • 当您需要一些特殊逻辑来设置时,可以更轻松地更改各个测试用例

  • 当您错过了一种转换类型时,更容易发现,因为方法名称更容易在核对清单中读取:)

  • (可疑)可能会更容易找到你的“神级”可能需要内部重构的地方,以便使用单独的子类来执行特定类型的转换(不是说你的方法是错的,但是你可能会发现一种类型的转换的逻辑非常讨厌;当你审查你的20或30个单独的测试用例时,这些测试用例可能会刺激子弹并开发更专业的转换器类)

希望有所帮助。

答案 1 :(得分:2)

正如您自己发现的那样使用数据提供者。在多个方法中复制完全测试用例没有任何好处,只需更改参数和期望。

就我个人而言,对于这种简单的案例,我确实从一种方法开始。我从一个简单的好案例开始,然后逐渐添加更多案例。我可能觉得不需要立即将其更改为数据提供者,因为它不会立即得到回报 - 但另一方面,事情可能会发生变化,而这种测试结构可能是需要重构的短期解决方案。

因此,每当您发现自己在这样的多测试用例方法中添加更多测试时,请停止使用数据提供程序进行测试。

相关问题