PHPUnit, проверить несколько значений - PullRequest
1 голос
/ 02 марта 2012

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

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 не выполняется, так как $ optionValue не является строкой (по умолчанию оно равно null)

Ответы [ 2 ]

2 голосов
/ 02 марта 2012

Вы делаете утверждения внутри своего звонка на 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}/')
        )
    )
);

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

1 голос
/ 02 марта 2012

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

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

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

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;
    }
}
...