Джанго + Питест + Селен

Недавно я перешел с классов 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, поскольку он не поддерживается и в противном случае проблематичен:

проблема с базой данных 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

Другие вопросы по тегам