Джанго + Питест + Селен
Недавно я перешел с классов Django TestCase на стороннюю систему pytest. Это позволило мне значительно ускорить мой набор тестов (в 5 раз), и в целом это был большой опыт.
У меня есть проблемы с селеном, хотя. Я сделал простое приспособление, чтобы включить браузер в мои тесты
@pytest.yield_fixture
def browser(live_server, transactional_db, admin_user):
driver_ = webdriver.Firefox()
driver_.server_url = live_server.url
driver_.implicitly_wait(3)
yield driver_
driver_.quit()
Но по какой-то причине база данных не сбрасывается должным образом между тестами. У меня тест похож на
class TestCase:
def test_some_unittest(db):
# Create some items
#...
def test_with_selenium(browser):
# The items from the above testcase exists in this testcase
Объекты, созданные в test_some_unittest
присутствуют в test_with_selenium
, Я не совсем уверен, как решить эту проблему.
2 ответа
Переключение с django.test.TestCase в пользу pytest означает использование плагина pytest-django, и ваши тесты должны выглядеть следующим образом:
class TestSomething(object):
def setup_method(self, method):
pass
@pytest.mark.django_db
def test_something_with_dg(self):
assert True
это, прежде всего, означает отсутствие наследования django.test.TestCase (который является производным от python std unittest framework).
@pytest.mark.django_db означает, что ваш тестовый сценарий будет выполняться в транзакции, которая будет отменена после ее завершения.
Первое появление маркера django_db также вызовет миграцию django.
Остерегайтесь использования вызовов базы данных в специальных методах pytest, таких как setup_method, поскольку он не поддерживается и в противном случае проблематичен:
def _django_db_fixture_helper(transactional, request, _django_cursor_wrapper):
if is_django_unittest(request):
return
if transactional:
_django_cursor_wrapper.enable()
def flushdb():
"""Flush the database and close database connections"""
# Django does this by default *before* each test
# instead of after.
from django.db import connections
from django.core.management import call_command
for db in connections:
call_command('flush', verbosity=0,
interactive=False, database=db)
for conn in connections.all():
conn.close()
request.addfinalizer(_django_cursor_wrapper.disable)
request.addfinalizer(flushdb)
else:
if 'live_server' in request.funcargnames:
return
from django.test import TestCase
_django_cursor_wrapper.enable()
_django_cursor_wrapper._is_transactional = False
case = TestCase(methodName='__init__')
case._pre_setup()
request.addfinalizer(_django_cursor_wrapper.disable)
request.addfinalizer(case._post_teardown)
Как я вижу, вы используете pytest-django (что хорошо). Из этого кода он не сбрасывает db, если он не транзакционный db. Таким образом, в ваших "других" тестах вам придется использовать транзакцию_db, и тогда он будет изолирован, как вы хотели.
Итак, ваш код будет выглядеть так:
class TestCase:
def test_some_unittest(transactional_db):
# Create some items
#...
def test_with_selenium(browser):
# The items from the above testcase does not exist in this testcase
Однако улучшение pytest-django может заключаться в том, что сброс выполняется до, а не после выхода значения фиксатора, что имеет гораздо больший смысл. Не так важно, что находится в процессе демонтажа, важно, чтобы настройка была правильной. В качестве побочного предложения, для фиксации браузера вы можете просто использовать плагин pytest-splinter