утвердить дилемму в классе юнит-тестирования - PullRequest
11 голосов
/ 21 мая 2011

Я хотел бы использовать функцию assert в PHP в моей среде модульного тестирования.Преимущество заключается в возможности видеть вычисляемое выражение (включая комментарии) в сообщении об ошибке.

Проблема в том, что каждый метод, содержащий тесты, может иметь более одного утверждения assert, и я хотел бы сохранитьотслеживать, сколько фактических утверждений assert было выполнено.assert не дает мне способа подсчитать, сколько раз он был запущен, только сколько раз он был неудачным (в рамках обратного вызова сбоя).

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

private function assertTrue($expression) {
    $this->testCount++;
    assert($expression);
}

Однако это не работает, поскольку любые переменные в выражении теперь находятся вне области видимости.

$var = true;
$this->assertTrue('$var == true'); // fails

Любые советы о том, как использовать assert вмое модульное тестирование, когда я могу посчитать количество реальных тестов?

Две идеи, которые я придумал, - заставить пользователей считать себя

$this->testCount++;
assert('$foo');
$this->testCount++;
assert('$bar');

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

Ответы [ 7 ]

2 голосов
/ 30 мая 2011

В PHPUnit все методы assert*() принимают дополнительный параметр $message, которым вы можете воспользоваться:

$this->assertTrue($var, 'Expected $var to be true.');

Если утверждение не выполнено, сообщение выводится с ошибкой вотчет после тестирования.

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

$this->assertTrue($var, 'Expected result of x to be true when y and z.');
2 голосов
/ 30 мая 2011

Немного нахальный ответ здесь, но откройте vim и наберите:

:%s/assert(\(.+\));/assert(\1) ? $assertSuccesses++ : $assertFailures++;/g

(В принципе, замените все assert() вызовы на assert() ? $success++ : $fail++;)

Более серьезно,предоставление механизма для подсчета тестов действительно является задачей, выходящей за рамки функции assert().Предположительно, вы хотите это для индикатора типа «X / Y тесты пройдены успешно».Вы должны делать это в рамках тестирования, записывая, что такое каждый тест, его результаты и любую другую информацию отладки.

1 голос
/ 30 мая 2011

Вы ограничены тем фактом, что assert() должны вызываться в той же области видимости, что и переменные, которые вы тестируете.Это оставляет - насколько я могу судить - решения, которые требуют дополнительного кода, модификации исходного кода перед выполнением (предварительной обработки) или решения, расширяющего PHP на уровне C.Это мое предлагаемое решение, которое включает дополнительный код.

class UnitTest {
    // controller that runs the tests
    public function runTests() {
        // the unit test is called, creating a new variable holder
        // and passing it to the unit test.
        $this->testAbc($this->newVarScope());
    }

    // keeps an active reference to the variable holder
    private $var_scope;

    // refreshes and returns the variable holder
    private function newVarScope() {
        $this->var_scope = new stdClass;
        return $this->var_scope;
    }

    // number of times $this->assert was called
    public $assert_count = 0;

    // our assert wrapper
    private function assert($__expr) {
        ++$this->assert_count;
        extract(get_object_vars($this->var_scope));
        assert($__expr);
    }

    // an example unit test
    private function testAbc($v) {
        $v->foo = true;
        $this->assert('$foo == true');
    }
}

Недостатки этого подхода: все переменные, используемые в модульном тестировании, должны быть объявлены как $v->*, а не $*, тогда как переменные записаны в операторе assertвсе еще пишутся как $*.Во-вторых, предупреждение, выданное assert(), не будет сообщать номер строки, по которой был вызван $this->assert().

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

1 голос
/ 25 мая 2011

Это не то, что предназначено для выполнения (помните, что оно возникло из скомпилированных языков). И семантика PHP тоже мало помогает в том, что вы пытаетесь сделать.

Но вы могли бы выполнить это с некоторыми синтаксическими издержками:

 assert('$what == "ever"') and $your->assertCount();

Или даже:

 $this->assertCount(assert('...'));

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

Это также не является обязательным (за исключением запуска прекомпилятора / регулярного выражения над тестовыми сценариями). Но я бы посмотрел на это с положительной стороны: не каждая проверка может быть достаточно значительной, чтобы гарантировать запись. Таким образом, метод обертки позволяет отказаться.

0 голосов
/ 29 мая 2011

Simple:

$this->assertTrue($var == true);

(без кавычек!)

Он будет оцениваться в пространстве вызывающего, поэтому assertTrue () будет передан просто false или true.

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

0 голосов
/ 24 мая 2011

Поскольку вы уже передаете выражение (которое может привести, поправьте меня, если я ошибаюсь, к цитированию ада):

$this->assertTrue('$var == true'); // fails with asset($expression);

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

$this->assertTrue(function() use ($var) {
  return $var == true;
}); // succeeds with asset($expression());
0 голосов
/ 21 мая 2011

Трудно дать ответ, не зная, как была построена ваша структура, но я попробую.

Вместо прямого вызова методов вашего класса модульного тестирования (таких методов, как assertTrue ()), вы можете использовать магический метод PHP __call () . Используя это, вы можете увеличивать внутренний счетчик каждый раз, когда вызывается метод assertTrue (). На самом деле, вы можете делать все, что хотите, каждый раз, когда вызывается любой метод Помните, что __call () вызывается, если вы пытаетесь вызвать метод, который не существует. Таким образом, вам придется изменить все имена ваших методов и вызвать их внутренне из __call (). Например, у вас есть метод с именем fAssertTrue (), но класс модульного тестирования будет использовать assertTrue (). Так как assertTrue () не определен, будет вызван метод __call (), и там вы будете вызывать fAssertTrue ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...