2012-03-02 6 views
1

Как вы тестируете несколько значений для одного и того же атрибута?PHPUnit, проверить несколько значений

class Test { 

    private $_optionalValue = null; 

    function setValue(String $optionalValue) 
    { 
     $this->_optionalValue = $optionalValue; 
    } 
} 

Так вот, "$ _optionalValue" может быть NULL или заданного пользователем, но когда я проверяю с PHPUnit, как это:

$optionalValue = PHPUnit_Util_Class::getObjectAttribute($my_object, '_optionalValue'); 

$this->assertThat(
    $optionalValue, 
    $this->logicalXor(
     $this->assertNull($optionalValue), 
     $this->logicalAnd(
      $this->assertAttributeInternalType('string', '_optionalValue', $optionalValue), 
      $this->assertRegExp('/[0-9]{2}:[0-9]{2}:[0-9]{2}/', (string) $optionalValue) 
     ) 
    ) 
); 

Regexp утверждение не потому, что $ optionalValue не является строкой (по умолчанию он равен нулю)

+2

Почему вы это проверяете этим странным способом? вы должны проверить поведение своего класса, а не внутреннее состояние. Задайте значение. Получите значение. Удостоверьтесь, что это то же самое. Это все, что вам нужно сделать. – Gordon

+0

@hakre, что случилось с XOR в его тесте? – meze

+0

Итак, вы бы тестировали сеттеры (что сложнее в моем случае) вместо установленного свойства? И btw я использовал XOR, потому что атрибут должен быть NULL XOR (строка И соответствие регулярному выражению) - я мог бы использовать OR, это было бы то же самое – kitensei

ответ

1

Вы проверяете частную собственность объекта, которого следует избегать, поскольку это внутренняя часть устройства, и вам не следует это волновать.

Если вашему устройству необходимо проверить значения этого класса, вполне вероятно, что обычно какое-то значение должно быть проверено.

Таким образом, вы можете инкапсулировать логику проверки в единицу ее собственной, например. a Вакцинатор:

class FooValueValidator implements Validator { 
    /** 
    * @var string 
    */ 
    private $value; 

    /** 
    * @var string 
    */ 
    private $regex = '/[0-9]{2}:[0-9]{2}:[0-9]{2}/'; 

    public function __construct($value) { 
     $this->value = $value; 
    } 

    /** 
    * @return bool 
    */ 
    public function isValid() { 

     if (is_null($this->value)) { 
      return TRUE; 
     } 

     if (!is_string($this->value)) { 
      return FALSE; 
     } 

     $result = preg_match($this->pattern, $this->value); 
     if (FALSE === $result) { 
      throw new Exception(sprintf('Regular expression failed.')); 
     } 
     return (bool) $result; 
    } 
} 

После этого вы можете написать модульные тесты для валидатора. Затем вы знаете, что ваш валидатор работает, и вы можете использовать его везде, где хотите.

class Test { 

    private $_optionalValue = null; 

    /** 
    * @var Validator 
    */ 
    private $_validator; 

    public function __construct(Validator $validator) { 
     $this->_validator = $validator; 
    } 

    function setValue(String $optionalValue) 
    { 
     if (!$this->validator->isValid($optionalValue)) { 
      throw new InvalidArgumentException(sprintf('Invalid value "%s".', $optionalValue)); 
     } 
     $this->_optionalValue = $optionalValue; 
    } 
} 
+0

приятное решение, принятое :) – kitensei

2

Вы делаете утверждения внутри вашего вызова assertThat, но вам нужно построить и передать в ограничениях вместо этого. Все методы, начинающиеся с assert, немедленно оценивают значение и генерируют исключение при несоответствии. Каждое утверждение имеет соответствующий класс ограничений, некоторые с заводским методом.

$optionalValue = PHPUnit_Util_Class::getObjectAttribute($my_object, '_optionalValue'); 

$this->assertThat(
    $optionalValue, 
    $this->logicalXor(
     $this->isNull(), 
     $this->logicalAnd(
      new PHPUnit_Framework_Constraint_IsType('string'), 
      new PHPUnit_Framework_Constraint_PCREMatch('/[0-9]{2}:[0-9]{2}:[0-9]{2}/') 
     ) 
    ) 
); 

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

+0

Действительно я буду разрабатывать свои тесты лучше, но спасибо за ответ, Я не знал об этом использовании. – kitensei

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