Хорошо когда код покрыт тестами. Хорошо когда кроме модульных тестов есть еще интеграционные, функциональные, UI-тесты и другие. Но должны ли тесты _всегда_ проходить успешно? Казалось бы, очевидный ответ - да. Но не все так просто...

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

К примеру, при написании когда, мы используем методологию TDD (Test Driven Development). В таком случае, только что написанные тесты никогда не выполнятся успешно, так как кода и функциональности, которую мы тестируем еще нет. Соответственно, если мы напишем n-е количество тестов, то наш билд нашего проекта всегда будет “failed”. Но при данном подходе это не должно мешать коммитить код в репозиторий и запускать все тесты автоматически на сервере CI. Вначале билд будет валиться, но с каждой реализованной фичей все больше тестов будет проходить успешно и ваш проект вскоре снова начнет собираться успешно.

Еще более интересная ситуация с тестами получается когда наше приложение использует сторонние библиотеки. Тут нам приходится работать с чужим кодом и/или со сторонней программой/API, исходников которой(го) у нас нет. Но тестировать-то надо. При этом у нас получаются интеграционные тесты, которые проверяют взаимодействие нашего кода с чужим.

В таком случае мы не можем контролировать работоспособность некоторых компонентов системы. Логично предположить, что тут тесты будут падать и это будет нормальным поведением. В большинстве случаев так и есть. Но бывают и другие ситуации:

Мы используем какой-то компонент SomeUsfulComponent, у которого должны быть две функции: FeatureA и FeatureB. И если хотя бы одна из них не работает, то тесты, которые проверяют взаимодействие нашей программы с этими функциями будут падать. А так как неработающие тесты на билд сервере - это поломанный билд, то дальше мы ничего делать уже не можем. Эта ситуация тоже вполне логичная. Вот только, например, мы в нашей программе можем обойтись без функции FeatureB. Как нам быть?

Тут, на мой взгляд, есть несколько решений данной проблемы. Привожу их в порядве “возрастания правильности”.

  1. Отключить тесты, которые падают из-за сторонних компонентов. Главный минус такого подхода - нужно помнить, что нужно когда-то проверить что эти тесты уже работают правильно и снова их включить.
  2. В процессе сборки проекта никак не реагировать на провалившиеся тесты. Если вы используете Jenkins, то на время можно сказать что при падении тестов продолжать дальше собирать билд. Минусы такого подхода - можно не увидеть, что упали другие тесты и продолжать спокойно работать.
  3. Учитывать в тестах, что FeatureB из SomeUsfulComponent бросает исключение NotImplementedException и в случае такого исключения говорить что тест выполнен успешно. В таком случае, как только FeatureB заработает корректно, наши тесты снова начнут падать и мы сможем быстро их исправить путем выкидывания ненужного уже кода.
  4. Сделать так, чтоб FeatureB работала :). Если это opensource проект, то тут все легче. Если исходников нет, но есть платная поддержка - получить рабочую версию как можно быстрее тоже можно, но не всегда. Иначе, скорее всего, ждать получится достаточно долго и обходится без нужной нам функциональности.


Comments

Андрей Светлов Ukraine

Friday, October 28, 2011 9:58 PM

Андрей Светлов

@unittest.expectedFailure
def test_something(self):
    pass

e0ne United States

Friday, October 28, 2011 10:50 PM

e0ne

Спасибо, классный вариант при использовании модуля unittests

Comments are closed