我的单元测试和django管理事务的方式存在问题。
在我的代码中,我有一个函数:
def send():
autocommit = transaction.set_autocommit(False)
try:
# stuff
finally:
transaction.rollback()
transaction.set_autocommit(autocommit)
在我的测试中,我有:
class MyTest(TransactionTestCase):
def test_send(self):
send()
我遇到的问题是我的test_send
成功通过,但不是80%的其他测试。
其他测试的交易似乎失败了
btw我正在使用py.test来运行我的测试
编辑: 当我仅使用测试运行时更清楚 myapp.test.test_module.py运行正常并且所有3个测试都通过但是当我运行所有测试时大部分失败,将尝试生成测试应用程序
我的所有测试都通过了django的默认测试运行器
EDIT2: 以下是测试此问题的最小示例:
class ManagementTestCase(TransactionTestCase):
def test_transfer_ubl(self, MockExact):
pass
class TestTestCase(TestCase):
def test_1_user(self):
get_user_model().objects.get(username="admin")
self.assertEqual(get_user_model().objects.all().count(), 1)
请记住,有一个数据迁移可以添加一个" admin" user(TestTestCase单独成功,但之前没有运行ManagmentTestCase)
似乎autocommit与它无关。
答案 0 :(得分:4)
TestCase
类将测试包装在两个原子块中。因此,如果您继承自transaction.set_autocommit()
,则无法使用transaction.rollback()
或TestCase
。
正如文档所说,如果您正在测试特定的数据库事务行为,则应使用TransactionTestCase
。
答案 1 :(得分:4)
autocommit = transaction.set_autocommit(False)
函数中{{}}感觉错误。在这里完成禁用事务可能是出于测试目的,但经验法则是将测试逻辑保留在代码之外。
正如@Alasdair指出的那样,django docs表示“出于性能原因,Django的TestCase类还会在事务中包装每个测试。”
从您的问题中不清楚您是否正在测试特定的数据库事务逻辑,如果是这种情况,那么@ Alasdair使用send
的答案是可行的。
否则,从TransactionTestCase
函数中的stuff
附近删除事务上下文切换应该会有所帮助。
由于您提到send
作为您的测试运行员,我还建议您使用pytest。 Pytest-django插件具有很好的功能,例如使用markers选择性地设置一些测试以进行交易。
pytest
如果安装插件太多,那么您可以滚动自己的pytest.mark.django_db(transaction=False)
夹具。像
transaction manage
您的 @pytest.fixture
def no_transaction(request):
autocommit = transaction.set_autocommit(False)
def rollback():
transaction.rollback()
transaction.set_autocommit(True)
request.addfinalizer(rollback)
将需要test_send
灯具。
no_transaction
答案 2 :(得分:1)
对于那些仍在寻找解决方案的人,serialized_rollback
选项是一种解决方法:
class ManagementTestCase(TransactionTestCase):
serialized_rollback = True
def test_transfer_ubl(self, MockExact):
pass
class TestTestCase(TestCase):
def test_1_user(self):
get_user_model().objects.get(username="admin")
self.assertEqual(get_user_model().objects.all().count(), 1)
来自docs
Django可以通过在
serialized_rollback
或True
的正文中将TestCase
选项设置为TransactionTestCase
来为每个测试案例重新加载数据,但是请注意这样会使测试套件的速度降低大约3倍。
很遗憾,pytest-django仍缺少此功能。