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

问题描述

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

像我期望的那样通过隔离运行测试

$ 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.objects.latest('created')而导致我尝试使用Object

是否有某种方法可以阻止Django将所有测试包装在测试运行程序中,从而阻止我的测试直接访问Object

解决方法

首先进行一些解释。

默认情况下,当您运行./manage.py test时,django test-runner会执行一些步骤,包括创建测试数据库(在app settings的每个数据库名称前加上test_前缀),运行迁移并销毁测试数据库(有关跑步者步骤的更多详细信息,请参见here

here

很好地解释了django如何对待测试数据库。

在您单独运行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看到它(django.TestCase it has时,原始unittest.TestCase不具有databases属性)

但是,当您调用整个模块(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,它将使用现有数据库,并且在测试运行后不会销毁它),并在应用设置中将test database name设置为{{3 }}(在这种情况下,它不会为测试数据库添加test_前缀)

  3. 由于您不想使用django.TestCase,所以根本不使用它们吗?将其替换为unittest.TestCase,它将不会创建测试数据库