Выделение тестов Pytest друг от друга - PullRequest
2 голосов
/ 08 марта 2019

Я работаю над быстро развивающимся проектом Python. В последнее время наш набор тестов стал несколько неуправляемым. Некоторые тесты не выполняются, когда модули, в которых они находятся, выполняются в неправильном порядке, несмотря на то, что они кажутся хорошо изолированными.

Я нашел несколько других вопросов по этому поводу, но они были связаны с приспособлениями:

Устройства Pytest, мешающие друг другу

тестовая изоляция между циклами гипотезы

Хотя мы также используем приборы, я не думаю, что проблема заключается в них, но, скорее всего, в том, что мы используем библиотеки, в которых классы имеют внутреннее состояние, которое изменяется при выполнении теста, например, mockito-python.

Я родом из мира Java, где этого не происходит, если вы явно не ставите свои тесты в зависимость друг от друга или не делаете какие-то сумасшедшие и необычные вещи. Следование тому же набору практик в Python привело меня к этим проблемам, и я понял, что, возможно, упускаю какое-то важное правило разработки тестов Python.

Можно ли сказать pytest удалить / вернуть / повторно инициализировать внутреннее состояние всех классов между различными запусками модулей?

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

Редактировать: Одна из выявленных нами проблем заключалась в том, что в тестовом файле были настроены некоторые объекты верхнего уровня, созданные mockito-python. Когда тесты были выполнены, сначала все файлы импортируются, а затем выполняются тесты. То, что случилось, было то, что один тест вызывал mockito.unstub(), который разрушает все макеты в фиктивном реестре mockito. Поэтому, когда тест был фактически выполнен, другой тест уже разрушил его макеты. Такое поведение довольно нелогично, особенно для неопытных разработчиков.

1 Ответ

2 голосов
/ 09 марта 2019

В python легко может случиться, что какое-то состояние будет изменено по ошибке. Например, при назначении списка переменной достаточно легко забыть добавить [:], когда необходимо создать копию списка.

x = [0,1,2,3,4,5]
y = x    # oops, should have been x[:]
y[2] = 7 # now we modify state somewhere...
x
=> [0, 1, 7, 3, 4, 5]

Одним из возможных подходов, по крайней мере, с большей вероятностью выявления таких проблем, может быть выполнение ваших юнит-тестов в случайном порядке. Я провел эксперимент, основанный на идее от https://stackoverflow.com/a/4006044/5747415:

import unittest
import random
def randcmp(_, x, y):
    return random.randrange(-1, 2)
unittest.TestLoader.sortTestMethodsUsing = randcmp

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

Может быть, стоит попробовать ...

...