Комментарии 9
В плюсы RF стоит записать также отличную документацию. Она действительно очень хорошо написана. Помню, как сам погружался во фреймворк несколько лет назад: скачал мануал, распечатал, взял с собой в междугородний автобус — и через 4 часа чтения уже нормально понимал, что и как в нём надо делать (либо хотя бы где именно в документации искать то, что мне потребуется). Мало какая библиотека сравнится с ним по этому параметру.
В рабочем проекте мы достаточно продуктивно использовали RF, но потом всё равно с него съехали. Причин было несколько, и все их тут вряд ли получится описать. Самая главная — разработчики писали проект на Java, и хотели что-то более близкое по языку (выбрали Spock в итоге). Но своё дело он сделал, и опыт работы с ним до сих пор приятно вспомнить.
С другой стороны, лично я в своих Python-проектах последних лет однозначно делал выбор не в его пользу, а всегда брал pytest. Оправдано ли это? Надо подумать....
Что касается следующего:
В xUnit фреймворках есть аннотации, заменяющие настройки suite setup, а в Pytest есть фикстуры со scope=”class”.
В Pytest тест-кейсы могут быть просто методами (и тогда у них нет никакого suite setup — т.е. нет единой подготовки). Если же нужна единая подготовка, мы можем обернуть эти методы в класс. Но если мы сделаем фикстуру со scope=”class” для этого класса (т.е. попытаемся реализовать suite setup), то получим отдельный инстанс класса для каждого теста, так что данные из suite setup никак не попадут в тест-кейсы. Отдельные инстансы, вероятно, создаются из предположения, что данные из разных тест-кейсов не должны влиять друг для друга. Но из-за этого настроить среду для выполнения тестов намного сложнее, чем в Robot Framework, где suite setup предусмотрен априори.
То кажется, что вы просто не поняли суть scopes. Они нужны не для того, чтобы указать, на какие тесты выполнять сетап (связи scope и применимости фикстур нет), речь идет о том, что иногда нужно выполнять код, и кешировать результат (т.е. не выполнять этот код на каждый тест в классе). Применимость этой ситуации довольно ограниченная, т.к. по-умолчанию считается, что все инициализации для каждого теста нужно делать с чистого листа, но в некоторых ситуациях (типа создаем соединения со сторонним сервисом, или запускаем сервер), альтернативы нет. Именно для этого и нужно указывать scopes, на практике, я ни разу не использовать scope с уровнем класса, обычно или используется дефолтный scope функции, либо сразу всей сессии целиком.
Чтобы применить одну и ту же фикстуру на класс, можно воспользоваться декоратором
@pytest.mark.usefixtures("yourfixturename")
class TestClass(TestCase):
pass
В этом случае, фикстура будет применена на все методы тесткейса, но инициализироваться она будет каждый раз с чистого листа. При этом, вовсе нет необходимости засовывать эти тест функции в класс в виде методов — с таким же успехом можно указать нужную фикстуру явно.
Если же, по каким-то причинам, явное указание не приемлемо (к примеру, потребуется отрефакторить сотню тестов), фикстуру можно применить автоматически внутри конкретного модуля, либо даже пакета:
@pytest.fixture(autouse=True)
def my_fixture():
pass
В целом, чтобы понять парадигму pytest, нужно разобраться с возможностями фикстур, т.к. благодаря им, переиспользования кода выполняется при помощи композиции объектов, вместо наследования.
Проблема тестовых классов в том, что setUp/tearDown порой становятся тяжелыми, и весь зоопарк объектов и моков запускается для всех тестовых методов класса:
![](https://habrastorage.org/webt/6c/c_/7f/6cc_7fe6qec2ikxe6-yzqfgyfvo.png)
Т.е., если у вас есть один маленький тестовый метод, для которого нужна половина этих объектов, все-равно будет вызван весь setUp и tearDown.
Pytest позволяет избежать этого, предлагая явно указывать только те фикстуры, которые нужны:
![](https://habrastorage.org/webt/6o/gn/cq/6ogncqk0z--pmcz7mivj47ydymm.png)
Если вы захотите переиспользовать setUp/tearDown между классами, то ситуация только усугубится, т.к. теперь вы будете создавать объекты из родительских классов:
![](https://habrastorage.org/webt/oz/b9/bw/ozb9bwh9-gonvp2k6e_ouctsjk4.png)
В случае с pytest, вы просто указывается что конкретно нужно для тестовой функции, т.е. имеете возможность выбрать фикстуры, как блоки от лего:
![](https://habrastorage.org/webt/f9/yy/zo/f9yyzonlosxbt6iq6a69sryau2c.png)
При этом, вы можете указывать зависимости фикстур одной от другой, объединяя их в цепь:
![](https://habrastorage.org/webt/ot/wr/oa/otwroact0rf7ty3-brdaut6qycm.png)
Но самое крутое, что фикстуры могут не только генерировать тестовые объекты, но еще и мокать библиотеки, используя синтаксис генераторов. При этом, фикстура в себе включает, как setUp часть, так и tearDown:
![](https://habrastorage.org/webt/pz/pe/gj/pzpegjagnk89m42srwrzqggisss.png)
Т.е. фикстуры представляют полноценную замену setUp/tearDown методам, при этом элегантно избегая проблемы божественного класса.
Есть еще и другие удобные плюшки в pytest, как параметрические тесты, локальные conftest конфигурации и плагины, но это уже больше детали.
В Pytest и ряде других xUnit фреймворков название тест-кейса всегда должно начинаться с test. Мне кажется логичным, когда используется метод test. Но в остальных случаях ограничения на наименования не помогают процессу.
Мне кажется эта идея довольно сомнительной, но если есть такая необходимость, то вы легко можете переопределить это поведение в конфигурации:
# content of pytest.ini
# Example 1: have pytest look for "check" instead of "test"
[pytest]
python_files = check_*.py
python_classes = Check
python_functions = *_check
Поскольку Pytest заточен под юнит-тестирование, реальные и тестовые методы приложения могут лежать в одном классе, так что возможна неразбериха.
Не должны! Тесты всегда лежат отдельно от кода. Но что касается pytest, то его интерфейс направлен на то, чтобы писать отдельные тестовые функции, а не классы. Поддержка классов нужна прежде всего для обратной совместимости с олдскульными юниттестами.
Пользовались на нескольких проектах когда-то роботом, совершенно не понравилось. Если мне память не изменяет, любой нетривиальный кейс превращался в нечитаемую портянку из текста на роботовском dsl и имплементации ключевых слов на питоне, между которыми приходилось постоянно переключаться. И нормальной поддержки в IDE тогда не было (сейчас может есть, не знаю).
Я так понимаю, что основная идея робота была в том, что тесты на нем смогут писать тестировщики, не умеющие писать код, но с нашими тестировщиками это явно не работало. Оказалось проще их обучить программированию.
К сожалению, ты не можешь приостановить выполнение в Robot Framework, чтобы посмотреть значения переменных.
Это вполне возможно, например, в связке Language Server Protocol для Robot Framework и VS Code
Robot Framework vs Pytest