- Взаимное влияние тестов
- Условные конструкции в тесте
- Тест вне тестов
- Слишком сильная детализация
- Код с тестами писать дольше, чем код без тестов?
Как и любой другой код, тесты можно писать по-разному — в том числе очень плохо. Помимо каких-то общих практик и стандартов кодирования у тестов есть свои особенности, о которых надо знать. В этом уроке мы пройдемся по некоторым из них.
Взаимное влияние тестов
Одно из ключевых правил — тесты не должны влиять друг на друга. Это значит, что любой тест выполняется так, как будто других тестов не существует в природе.
Нарушить это правило очень просто. Один тест может создать файл, изменить переменную или записать что-то в базу. Если остальные тесты наткнутся на эти изменения, то они могут работать неверно, например:
- Упасть там, где не должны падать
- Успешно пройти там, где не должны проходить
Кроме этого, в такой ситуации вводится неопределенность. Такие тесты могут падать без видимых причин. Например, когда тест запускают изолированно, он работает, а когда вместе с остальными — падает:
user = None
def test_first():
user = { 'name': 'Vasya' }
# Тут логика теста
def test_second():
# Используется пользователь, созданный другим тестом
# Этот тест зависит от того, как работает предыдущий тест
# Он не может работать без последовательного запуска обоих тестов
user["name"] = 'Petya'
Особенно часто такая ситуация возникает в тестах, активно взаимодействующих с внешней средой: базой данных или файловой системой. Тестирование побочных эффектов имеет свои хитрости, которые мы рассматриваем в курсе по продвинутому тестированию.
Условные конструкции в тесте
def test_something():
if (something):
# Выполняем код одним способом
# Проверка может быть тут
else:
# Выполняем код другим способом
# Проверка может быть тут
# Проверка может быть тут
Любое ветвление в тестах — это фактически несколько тестов в одном. Ветвления порождают код, который сам нуждается в тестировании. Так происходит, потому что порядок выполнения становится не очевидным — его можно случайно нарушить. Лучше создать независимые тесты для каждой ветки.
Тест вне тестов
Задача фикстур — готовить данные и среду для тестирования, а задача тестовых функций — проводить проверки и вызывать код для тестирования. Но иногда разработчики переусердствуют:
# Тестируем функцию sum()
import pytest
@pytest.fixture
def result():
# Вызывается тестируемый код
return sum([5, 9])
def test_sum(result):
assert result == 14
В этом примере тестируемый код вызывается в функции result()
. Такой подход усложняет анализ тестов, потому что переворачивает все с ног на голову.
Слишком сильная детализация
Некоторые программисты стремятся максимально разносить код по файлам, модулям и функциям. То же самое наблюдается и в тестах. Вместо одного теста со всеми необходимыми проверками, они создают пять тестов, в каждом из которых ровно одна проверка:
def test_create_user():
user = { 'name': 'Mark', 'age': 28 }
# Код, добавляющий пользователя в базу данных
assert user['age'] == 28
def test_create_user():
user = { 'name': 'Mark', 'age': 28 }
# Код, добавляющий пользователя в базу данных
assert user['name'] == 'Mark'
У такого разделения есть одно последствие — кода станет больше, а значит сложнее будет провести рефакторинг в будущем.
Код с тестами писать дольше, чем код без тестов?
Это очень интересный вопрос, по которому можно понять, насколько хорошо программист умеет писать тесты.
Некоторые виды тестирования действительно сложны и требуют дополнительного времени. Но при этом ежедневные тесты, которые пишутся вместе с кодом, должны приводить к ускорению разработки. И на это есть свои причины:
- Тесты помогают раньше выявить неудачные решения и поэтому влияют на дизайн кода
- Тесты упрощают подготовку входных данных — ее нужно сделать всего один раз
- Тесты упрощают проверку результата работы кода, ведь сами проверяют все, в том числе и пограничные случаи
- Регулярные тесты упрощают и ускоряют рефакторинг, потому что с ними не приходится проверять части кода вручную
- Тесты улучшают атмосферу в команде, потому что снижают уровень стресса
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.