Подтвердить что ты не робот

PHPUnit: несколько утверждений в одном тесте, только первый сбой

Следующая странность, которую я вижу с помощью 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 сбой. Хорошо.

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

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

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

4b9b3361

Ответ 1

Прежде всего: это ожидаемое поведение.

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

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

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, пока я не занимаюсь (и я не уверен, нравится ли мне это) Я хотел бы это отметить;)

Ответ 2

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

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

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

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

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