【问题标题】:Django pytest: Clear DB after a running a test caseDjango pytest:运行测试用例后清除数据库
【发布时间】:2017-03-20 12:58:50
【问题描述】:

我有一个测试(django pytest)需要操作数据库中的对象。问题是在测试之后,数据库是“脏的”,其他测试失败。 我看到了一些关于 TransactionTestCase 的东西,但我不明白它是如何与 django 测试一起工作的。

这是我当前代码的一个简单示例:

@pytest.mark.django_db
def test_something(mock_my_obj):
    mock_my_obj.save()
    # test test test
    ...
    # I don't want to delete the obj here...

更新: 第二次尝试:我读到TestCase 应该使用事务并为每个测试回滚它们。不适合我:

from django.test import TestCase

class MyTests(TestCase):
    def test_yair_a(self):
        print 'AAAAAAA'
        print Account.objects.all()
        Account.objects.create(account_id=1,account_name='1')
        print Account.objects.all()

    def test_yair_b(self):
        print 'BBBBBBBB'
        print Account.objects.all()
        Account.objects.create(account_id=2,account_name='2')
        print Account.objects.all()

结果(有趣的部分):

> py.test -s -v -k test_yair
AAAAAAA
[]
[<Account: 1>]
PASSED

BBBBBBBB
[<Account: 1>]
[<Account: 1>, <Account: 2>]
PASSED

表示在 test_a 结束时没有事务回滚。

【问题讨论】:

  • 这很奇怪。 The docs 声明测试事务在每次测试后回滚。也许它与您注入对象有关,而不是在测试函数本身中创建它。
  • 我不这么认为 - 模拟只是一个对象。我将它保存到测试本身的数据库中
  • 你能发一个minimal working example吗?
  • 按照我理解文档的方式,TestCase 为类中的所有测试保留数据库,然后将它们回滚。请为您的简单 pytest 测试发布 MWE。
  • @NilsWerner 因为我使用 django,所以 MWE 将包含模型文件和 django 设置。我认为我的示例非常简单明了。

标签: python django pytest-django


【解决方案1】:

问题是默认情况下 django 在默认数据库上创建一个事务。我需要在另一个数据库上进行交易。这是我的设置文件:

ROOT_PASS = 'ohnoyoudidnt'
ROOT_USER = 'root'
ROOT_HOST = 'localhost'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'default_db',
        'USER': ROOT_USER,
        'PASSWORD': ROOT_PASS,
        'HOST': ROOT_HOST,
        'PORT': '3306',
    },
    'my_app': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'my_app_db',
        'USER': ROOT_USER,
        'PASSWORD': ROOT_PASS,
        'HOST': ROOT_HOST,
        'PORT': '3306'
    },

要解决这个问题,需要使用transaction.atomic(using='my_app') 块,并在其中抛出错误以进行回滚。自然我想为此编写一个装饰器,但是将它与 pytest 一起使用并不像我最初想象的那么简单,因为 pytest 本身在我的代码之前操纵方法(使用模拟和补丁时)。

花了几个小时后,我得到了这个可以工作的装饰器!

from decorator import decorator
import pytest
from django.db import transaction


class TestTempException(Exception):
    pass


def testing_w_transaction(using):
    def testing_w_transaction_inner(function):
        def func_wrapper(f, *args, **kwargs):
            try:
                with transaction.atomic(using=using):
                    f(*args, **kwargs)
                    raise TestTempException()
            except TestTempException:
                pass
        return decorator(func_wrapper, pytest.mark.django_db(function))
    return testing_w_transaction_inner

用法:

@testing_w_transaction(using='my_app')
def test_my_method(mock_object, ...):
     # test test test

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 2011-06-04
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多