PHPUnit: несколько утверждений в одном тесте, только первый сбой замечен - PullRequest
14 голосов
/ 13 апреля 2011

Следующая странность, которую я вижу с PHPUnit:

class DummyTest extends PHPUnit_Framework_TestCase {
    public function testDummy() {
        $this->assertTrue(false, 'assert1');
        $this->assertTrue(false, 'assert2');
    }

    public function testDummy2() {
        $this->assertTrue(false, 'assert3');
    }
}

Как только первое утверждение не выполняется в тесте, остальная часть теста игнорируется.

Итак (спростой вызов phpunit DummyTest.php ):

  • Приведенный выше код отобразит 2 теста, 2 утверждения, 2 сбоев.Что?

  • Если я выполню все тесты успешно, то все будет в порядке (2 теста, 3 утверждения).Хорошо.

  • Если я только выполню все тесты, кроме assert2, я получу 2 теста, 3 утверждения, 1 сбой.Хорошо.

Я не понимаю, но PHP уже давно существует, конечно, это должен быть я?

Мало того, что счет не то, что яя ожидаю, что в первом коде будет отображаться только сообщение об ошибке для первого неудачного утверждения.

(Кстати, я анализирую формат xml, сгенерированный PHPUnit для CI, а не проверяю реальный код, поэтому и практикуетсянесколько утверждений в одном тесте.)

Ответы [ 2 ]

31 голосов
/ 13 апреля 2011

Во-первых: это ожидаемое поведение.

Каждый метод тестирования прекращает выполнение , если утверждение не выполнено.

Для примера, где напротив будет очень раздражающим *:

class DummyTest extends PHPUnit_Framework_TestCase {
    public function testDummy() {
        $foo = get_me_my_foo();
        $this->assertInstanceOf("MyObject", $foo);
        $this->assertTrue($foo->doStuff());
    } 
}

если phpunit не остановится после первого утверждения, вы получите E_FATAL (вызов функции, не являющейся членом), и весь процесс PHP умрет.

Так что формулировать хорошие утверждения и небольшие тесты более практично.

Для другого примера:

Когда «утверждая, что массив имеет размер X, а затем утверждая, что он содержит a, b и c », вас не волнует тот факт, что он не содержит этих значений, если размер 0.

Если тест не пройден, вам обычно просто нужно сообщение «почему он провалился», а затем, исправляя его, вы автоматически убедитесь, что остальные утверждения также пройдены.


На дополнительном примечании есть также люди, которые утверждают, что вы должны иметь только One Asssertion per Test case, пока я не практикуюсь (и я не уверен, нравится ли мне это), я хотел это отметить; )

10 голосов
/ 14 апреля 2013

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

Я использую это для веб-страниц тестирования Selenium. Поэтому я могу утверждать, что нахожусь в нужном месте каждый раз, когда перехожу на новую страницу. Например, если я зайду на веб-страницу, затем войду в систему, а затем изменю свой профиль, я буду утверждать, что попал в нужное место, когда вошел в систему, потому что тест больше не будет иметь смысла, если мой вход не пройден. Это не позволяет мне получать дополнительные сообщения об ошибках, когда на самом деле была обнаружена только одна проблема.

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

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

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

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