Предположим, у меня есть класс с частным свойством и связанным с ним публичным getter и setter. Я хочу проверить с помощью PHPUnit, что свойство получает правильное значение после использования setter или что getter возвращает правильное свойство.
Конечно, я могу проверить сеттер, используя геттер, чтобы увидеть, что объект хранит правильное значение, и наоборот для тестирования геттера. Однако это не гарантирует, что частная собственность является той, которая установлена.
Скажем, у меня был следующий класс. Я создал свойство, getter и setter. Но я сделал опечатку в названии свойства, поэтому геттер и сеттер фактически не манипулируют имуществом, которое они предназначены для манипулирования
class SomeClass { private $mane = NULL; // Was supposed to be $name but got fat-fingered! public function getName () { return ($this -> name); } public function setName ($newName) { $this -> name = $newName; return ($this); } }
Если я запустил следующий тест
public function testSetName () { $this -> object -> setName ('Gerald'); $this -> assertTrue ($this -> object -> getName () == 'Gerald'); }
Я бы получил пропуск. Однако на самом деле случилось что-то очень плохое, чего я не хочу. Когда вызывается setName (), он фактически создает новое свойство в классе с именем, которое, по моему мнению, имело мое личное свойство, только тот, который создает сеттер, является общедоступным! Я могу показать, что со следующим кодом:
$a = new SomeClass; $a -> setName('gerald'); var_dump ($a -> getName ()); var_dump ($a -> name);
Он будет выводить:
строка (6) "gerald"
строка (6) "gerald"
Можно ли каким-либо образом получить доступ к приватным свойствам из PHPUnit, чтобы я мог писать тесты, чтобы убедиться, что свойства, которые, как мне кажется, получают и устанавливаются на самом деле, действительно получают и устанавливают?
Или есть еще одна вещь, которую я должен делать в тесте, чтобы поймать такие проблемы, не пытаясь получить доступ к частному состоянию тестируемого объекта?
Для тестирования свойств я бы сделал те же аргументы, которые я делаю, а затем говорю о тестировании частных методов.
You usually don't want to do this
.
Речь идет о тестировании наблюдаемого поведения.
Если вы переименуете все свои свойства или решите сохранить их в массиве, вам не нужно будет полностью адаптировать ваши тесты. Вы хотите, чтобы ваши тесты говорили вам, что все еще работает ! Когда вам нужно изменить тесты, чтобы убедиться, что все еще работает, вы теряете все преимущества, так как вы также можете сделать ошибку, изменяя тесты.
Итак, в целом, вы теряете ценность своего тестового набора!
Просто тестирование комбинаций get / set было бы достаточно, но обычно не каждый сеттер должен иметь getter, а просто создавать их для тестирования – это не простой эфир.
Как правило, вы устанавливаете некоторые вещи, а затем говорите методу DO
(поведение) что-то. Тестирование для этого (что класс делает то, что должно делать) является наилучшим вариантом для тестирования и должен сделать проверку свойств излишней.
Если вы действительно хотите сделать это, есть функция setAccessible
в API рефлексии PHP, но я не могу составить пример, где я считаю это желательным
Детектор PHP Mess как UnusedPrivateField Rule
class Something { private static $FOO = 2; // Unused private $i = 5; // Unused private $j = 6; public function addOne() { return $this->j++; } }
Это приведет к двум предупреждениям, потому что переменные никогда не доступны
Вы также можете использовать Assert::assertAttributeEquals('value', 'propertyName', $object)
.
См. https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L490
Я согласен с другими, что в целом вы хотите избежать доступа к частным лицам в своих тестах, но для случаев, когда вам нужно, вы можете использовать отражение, чтобы читать и писать свойство .
Я просто хочу отметить одно. Давайте забудем о частных полях на мгновение и сосредоточимся на том, что заботит клиент вашего класса. Ваш класс предоставляет контракт, в данном случае – возможность изменять и получать имя (через getter и setter). Ожидаемая функциональность проста:
setName
в "Gerald"
, я ожидаю получить "Gerald"
когда я вызываю getName
Это все. Клиент не будет (ну, не стоит!) Заботиться о внутренней реализации. Используете ли вы имя частного поля, hashset или называете веб-сервис через динамически сгенерированный код – не имеет значения для клиента. Ошибка, с которой вы в настоящее время сталкиваетесь, с точки зрения пользователя – не является ошибкой.
Является ли PHPUnit проверять частные переменные – я не знаю. Но с точки зрения модульного тестирования вы не должны этого делать.
Изменить (в ответ на комментарий):
Я понимаю ваши опасения по поводу возможного воздействия внутреннего состояния, однако я не думаю, что модульное тестирование – это правильный инструмент для решения этого. Вы можете придумать множество возможных сценариев, как что-то может сделать что-то еще, что не было запланировано. Единичные тесты ни в коем случае не вылечиваются для всех и не должны использоваться как таковые.