Учитывая следующие два (простой / случайный) 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;
}
Две части вопроса:
Возможно, что function2 () может быть вызвана другими функциями, кроме function1 ().
С одной стороны, я думаю, что функция должна проверять все, что ей дано. С другой стороны, я чувствую, что это может привести к большому количеству дубликатов и (хотя и не с этими конкретными функциями) дорогостоящего кода.
Это действительно не имеет значения, если function1
проверяет параметр c
или нет, это в значительной степени стилистический выбор. Некоторым людям нравится выполнять ВСЕ проверки в начале функции, потому что это означает, что функция может быть прервана как можно скорее, без какой-либо ненужной обработки. Если перед вызовом произошла значительная обработка function2
тогда было бы больше оснований для проверки, но в данном случае важно то, что параметр проверяется до его фактического использования.
Что касается вашего второго вопроса, ДА, вы должны проверить передачу неверного параметра в function1
, Лично я не думаю, что вы должны тестировать передачу плохого параметра в function2
, На самом деле, с точки зрения модульного теста, вы даже не должны знать, что function2
существует.
Я не программист на PHP, поэтому не стесняйтесь голосовать «за», если это далеко не так, но на основе других языков, которые я использовал, публичные методы класса определяют открытый интерфейс и, следовательно, тестируемый 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
поделиться функциональностью с другими безопасными методами, зная, что ваши тесты общедоступного интерфейса проверяют, что класс по-прежнему работает с клиентами, как и ожидалось. Отсюда и термин «с уверенностью рефакторинг», который вы время от времени слышите.
Если вы начнете тестировать все свои приватные методы, то в итоге вы будете тесно связывать свои тесты с реализацией (а не с поведением) или вашими классами. Это значительно усложнит вам рефакторинг кода, не нарушая тесты, и вы сможете достичь того момента, когда тесты будут больше накладными расходами, чем выгодой.
Других решений пока нет …