Django 测试运行程序不尊重 unittest.TestCase?

Django test runner not respecting unittest.TestCase?

对于我的一个功能测试,我决定使用 unittest.TestCase 而不是 Django 测试 class 因为清理测试时直接访问我的本地开发数据库很方便测试本身。

运行 隔离测试像我预期的那样通过了:

$ python manage.py test functional_tests.test_functionality
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.040s

OK

然而,当我尝试同时 运行 所有测试时,该测试特别出错,抱怨对象 DoesNotExist,就好像它正在使用 Django 测试数据库一样:

$ python manage.py test functional_tests
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..................E..
======================================================================
ERROR: some_functional_test (functional_tests.test_functionality.FunctionalTest)
----------------------------------------------------------------------
Traceback (most recent call last):

... etc.

app.models.Object.DoesNotExist: Object matching query does not exist.

----------------------------------------------------------------------
Ran 21 tests in 0.226s

FAILED (errors=1)
Destroying test database for alias 'default'...

我认为当 Django 的测试数据库中不存在 Object 时我尝试使用 Object.objects.latest('created') 时出现错误。

有什么方法可以防止 Django 将所有测试包装在关于测试 运行ner 的所有测试中,从而阻止我的测试直接访问 Object

先稍微解释一下。

默认情况下,当您 运行 ./manage.py test django test-runner 执行一些涉及创建测试数据库的步骤时(每个数据库名称都带有 test_ 前缀,来自 app settings), running migration and destroying test database (more details on runner steps could find here)

描述了django如何处理测试数据库的一个很好的解释here


在您 运行 unittest.TestCase 孤立的情况下 没有 创建测试数据库:

$ python manage.py test functional_tests.test_functionality
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.040s

OK

(^没有关于创建测试数据库的日志)

那是因为没有 django.test.TestCase 调用。从sources (virgin unittest.TestCase doesn't have databases property, when django.TestCase it has)

可以看出

但是当您调用整个模块 (python manage.py test functional_tests) 时,您似乎在套件中进行了一些 django.test.TestCase 测试,这就是创建新测试数据库的原因:

$ python manage.py test functional_tests
Creating test database for alias 'default'...  # <-- THIS ONE
##<skipped for readability>
Destroying test database for alias 'default'...

正如您提到的,测试失败是因为没有为它们准备好的对象。


解决方案

此时我看到解决这个问题的选项很少。

  1. 明确地为测试准备测试数据(通过 fixtures 或在测试或设置中手动)以便它们独立于数据库的当前状态

  2. 明确使用所需的数据库。

    运行 使用 --keepdb 选项进行测试(即 ./manage.py test --keepdb,它将使用现有数据库并且不会在测试 运行s 后销毁它)并设置相同的 test database name in app settings as working database(在这种情况下,它不会为测试数据库附加 test_ 前缀)

  3. 既然不想用django.TestCase,那干脆不用?用 unittest.TestCase 替换它们,它不会创建测试数据库