在同一个类中给出以下两个(简单/随机)PHP方法:
/*
* @param $a An int to play with
* @param $b An int to play with
* @param $c An int to play with
*
* @throws InvalidArgumentException when either $a, $b, or $c are not an int
*
* @return A new int
*/
public function1($a, $b, $c) {
if(!is_int($a)) throw new InvalidArgumentException('$a must be an int');
if(!is_int($b)) throw new InvalidArgumentException('$b must be an int');
$x = $a * $b;
$y = $this->function2($c);
return $x - $y;
}
/*
* @param $c An int to play with
*
* @throws InvalidArgumentException when $c is not an int
*
* @return A new int
*/
private function2($c) {
if(!is_int($c)) throw new InvalidArgumentException('$c must be an int');
return $c + 1;
}
两个问题:
除了function1()之外,其他函数可能会调用function2()。
一方面,我认为一个函数应该检查给它的一切。另一方面,我觉得它可能导致大量重复和(虽然没有这些特定功能)昂贵的代码。
答案 0 :(得分:1)
function1
检查参数c
是否真的无关紧要,它在很大程度上是一种风格选择。有些人喜欢在函数开始时执行ALL检查,因为这意味着函数可以尽快中止,而不会进行任何不必要的处理。如果在调用function2
之前有重要的处理,那么检查会有更多的理由,但是重要的是在实际使用之前检查参数。
就你的第二个问题而言,是的,你应该测试将错误的参数传递给function1
。就个人而言,我不认为你应该测试将错误的参数传递给function2
。事实上,从单元测试的角度来看,你甚至不应该知道function2
存在。
我不是PHP程序员,所以如果偏离基础可以随意投票,但基于我使用过的其他语言,类的公共方法决定了公共接口,因此该类的 testable api 。换句话说,如果我是您班级的客户,我可以调用您班级的任何公共方法,包括function1
。当客户调用公共方法时,可以测试某些期望(输入/输出/处理),但客户不应该知道或关心这些期望是通过一种方法还是通过使用来满足/强制执行的多种方法。因此,从客户的角度来看,您的代码可能是这样编写的:
/*
* @param $a An int to play with
* @param $b An int to play with
* @param $c An int to play with
*
* @throws InvalidArgumentException when either $a, $b, or $c are not an int
*
* @return A new int
*/
public function1($a, $b, $c) {
if(!is_int($a)) throw new InvalidArgumentException('$a must be an int');
if(!is_int($b)) throw new InvalidArgumentException('$b must be an int');
if(!is_int($c)) throw new InvalidArgumentException('$c must be an int');
$x = $a * $b;
$y = $c + 1;
return $x - $y;
}
如果您最初编写了这样的代码并针对此行为编写了测试,则可以通过添加function2
与其他方法共享功能来重构您的代码,这些方法可以安全地了解您的公开信息接口测试确保类仍然按预期执行到客户端。这就是“充满信心地重构”一词的地方。你不时会听到的。
如果您开始测试所有私有方法,那么您最终会将测试与实现(而不是行为)或类紧密耦合。这使得您在不破坏测试的情况下重构代码变得更加困难,并且您可以达到测试更多的开销而非利益的程度。