2012-03-20 3 views
2

как бы вы протестировали метод класса, который имеет побочные эффекты через self::? таких как:классы unittest, которые используют self :: in PHP

final class Foo{ 
    private static $effect = false; 
    public static function doit($arg){ 
     if(self::effect) return; 
     self::check_args($arg); 
     self::$effect = true; 
    } 
    private function check_args($arg){ 
     #validate and trhow exception if invalid 
    } 
} 

Я должен отправить несколько арг на Doit(), чтобы проверить это правильно проверки значения, но после первого запуска, это просто обойти его. это в основном метод инициализации для singleton, который устанавливает инициализированный флаг.

Я пока не могу позволить себе возиться с классом. Есть ли способ сделать копию/instatiate объекта таким образом, чтобы он работал с self::?

+0

Это недопустимый синтаксис. – Jon

+1

Вы попробовали опцию -static-backup в PHPUnit? – SamHennessy

+0

@SamHennessy, который, кажется, идет в правильном направлении, но я не смог найти больше информации об этом. от http://www.phpunit.de/manual/3.6/en/textui.html он перенаправляет меня на http://www.phpunit.de/manual/3.6/en/fixtures.html#fixtures.global-state, который вообще не уточняет этот флаг. Я попытался запустить тест с флагом, но он как и раньше. – gcb

ответ

2

Класс должен быть переписан:

class Foo{ 
    private $effect = false; 
    public function doit($arg){ 
     if($this->effect) return; 
     $this->check_args($arg); 
     $this->effect = true; 
    } 
    private function check_args($arg){ 
     #validate and trhow exception if invalid 
    } 
} 

self:: используется только для static функций и переменных, которые вы должны избегать использования в большинстве случаев по различным причинам.

+0

, но я забыл «статические» ключевые слова при вводе этой более простой версии класса. вопрос, который я думаю, - это еще раз повторить инициализацию объявления объекта, чтобы проверить его с несколькими параметрами инициализации при одном запуске phpunit. – gcb

+0

@ gbc Люди обычно говорили вам, что использование статики в большинстве случаев - это плохая практика. Это в основном то же самое, что и глобальная переменная. Это означает, что одна и та же функция может не иметь одного и того же результата в зависимости от состояния глобальной переменной. Кто-то может вводить что-то в любую часть вашего кода, что вызывает ошибку, и вы никогда не сможете ее найти. Имеет ли это смысл? Есть несколько случаев, когда их можно использовать без проблем, например, реестр объектов. Статику также, как известно, трудно подвергнуть тестированию. Я бы предложил узнать об инъекции зависимостей вместо использования глобальной статики. – dqhendricks

+0

Я согласен со всем этим. но я был привлечен к этому проекту. Я пытаюсь написать тесты для проекта, чтобы затем нажать на рефакторинг. – gcb

1

Как насчет добавления в тестовую среду подкласса тестируемого класса и последующего использования его для управления вашей статической переменной. В приведенном ниже примере я изменил код немного, так что значение $ эффекта легче играть, и я также должен был врезаться сферой $ эффекта защищено:

<?php 
class Foo{ 
    protected static $effect = "0"; 
    public static function doit($arg) { 
     echo 'I got: ' . $arg . ' and effect is: ' . self::$effect . '<br>'; 
     self::$effect = "1"; 
    } 
} 

class FooChild extends Foo { 
    public static function setEffect($newEffect) { 
     self::$effect = $newEffect; 
    } 
} 

Foo::doit('hello'); 
Foo::doit('world'); 
FooChild::setEffect('3'); 
Foo::doit('three'); 

Выход заключается в следующем:

я получил: Привет и эффект: 0 (первый раз через показывает начальное значение)

я: мир, и эффект: 1 (второй раз через показывает значение увеличивается на Foo в Doit()

Я получил: три и эффект: 3 (третий раз, показывает, что подклассы s удалось изменить значение в родительском элементе)

+0

Отличная идея! это не может быть лучшим чистым unittest (не только вы не тестируете только один метод, но вы добавляете новые методы) ... но может решить более непосредственную проблему. и в конце концов, основная проблема, с которой я согласен, вначале состоит в исходном коде. Спасибо, я реализую это, пока кто-то не укажет на лучший шаблон (если это возможно в этом случае) – gcb

+0

Ну, разница в том, что дочерний класс будет жить в вашем мире тестирования, а не в производственном коде. Поэтому я считаю, что это часть тестового оборудования. Не отличается от кода, который вы бы поставили в тестовую настройку или срыв. Аналогичная тактика заключается в использовании шва, см .: http://stackoverflow.com/questions/7210851/phpunit-how-to-mock-todays-date-without-passing-it-as-an-argument/7410887#7410887 Но со статикой вещи немного сложнее. –

Смежные вопросы