{"title":"进阶测试主题","version":"3.2","locale":"zh-hans","docname":"topics/testing/advanced","url":"/zh-hans/3.2/topics/testing/advanced/","canonical":"https://djangodocs.dev/zh-hans/3.2/topics/testing/advanced/","summary":"RequestFactory 与测试客户端共享相同的 API。但是，RequestFactory 不能像浏览器那样运行，而是提供一种生成请求实例的方法，该实例可用作任何视图的第一个参数。","html":"<h1>进阶测试主题<a class=\"heading-anchor\" href=\"#advanced-testing-topics\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<section id=\"the-request-factory\">\n<h2>请求工厂<a class=\"heading-anchor\" href=\"#the-request-factory\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.RequestFactory\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">RequestFactory</span><a class=\"heading-anchor\" href=\"#django.test.RequestFactory\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><a class=\"reference internal\" href=\"#django.test.RequestFactory\" title=\"django.test.RequestFactory\"><code class=\"xref py py-class docutils literal notranslate\">RequestFactory</code></a> 与测试客户端共享相同的 API。 但是，RequestFactory 不能像浏览器那样运行，而是提供一种生成请求实例的方法，该实例可用作任何视图的第一个参数。 这意味着您可以像测试任何其他功能一样测试视图函数——就像一个黑匣子一样，具有确切已知的输入，可以测试特定的输出。</p>\n<p><a class=\"reference internal\" href=\"#django.test.RequestFactory\" title=\"django.test.RequestFactory\"><code class=\"xref py py-class docutils literal notranslate\">RequestFactory</code></a> 的 API 是测试客户端 API 的一个稍加限制的子集。</p>\n<ul class=\"simple\">\n<li><p>它只能访问 HTTP 的 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">get()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.post\" title=\"django.test.Client.post\"><code class=\"xref py py-meth docutils literal notranslate\">post()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.put\" title=\"django.test.Client.put\"><code class=\"xref py py-meth docutils literal notranslate\">put()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.delete\" title=\"django.test.Client.delete\"><code class=\"xref py py-meth docutils literal notranslate\">delete()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.head\" title=\"django.test.Client.head\"><code class=\"xref py py-meth docutils literal notranslate\">head()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.options\" title=\"django.test.Client.options\"><code class=\"xref py py-meth docutils literal notranslate\">options()</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.Client.trace\" title=\"django.test.Client.trace\"><code class=\"xref py py-meth docutils literal notranslate\">trace()</code></a> 方法。</p></li>\n<li><p>这些方法接受所有相同的参数，<em>除了</em> <code class=\"docutils literal notranslate\">follow</code>。因为这只是一个产生请求的工厂，所以由你来处理响应。</p></li>\n<li><p>它不支持中间件。如果需要视图正常运行，会话和认证属性必须由测试本身提供。</p></li>\n</ul>\n<section id=\"example\">\n<h3>例如<a class=\"heading-anchor\" href=\"#example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>下面是一个使用请求工厂的单元测试：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> AnonymousUser<span class=\"p\">,</span> User\n<span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> RequestFactory<span class=\"p\">,</span> TestCase\n\n<span class=\"kn\">from</span> <span class=\"nn\">.views</span> <span class=\"kn\">import</span> MyView<span class=\"p\">,</span> my_view\n\n<span class=\"k\">class</span> <span class=\"nc\">SimpleTest</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">setUp</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Every test needs access to the request factory.</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>factory <span class=\"o\">=</span> RequestFactory<span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>user <span class=\"o\">=</span> User<span class=\"o\">.</span>objects<span class=\"o\">.</span>create_user<span class=\"p\">(</span>\n            username<span class=\"o\">=</span><span class=\"s1\">&#39;jacob&#39;</span><span class=\"p\">,</span> email<span class=\"o\">=</span><span class=\"s1\">&#39;jacob@…&#39;</span><span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"s1\">&#39;top_secret&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_details</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Create an instance of a GET request.</span>\n        request <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>factory<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customer/details&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Recall that middleware are not supported. You can simulate a</span>\n        <span class=\"c1\"># logged-in user by setting request.user manually.</span>\n        request<span class=\"o\">.</span>user <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>user\n\n        <span class=\"c1\"># Or you can simulate an anonymous user by setting request.user to</span>\n        <span class=\"c1\"># an AnonymousUser instance.</span>\n        request<span class=\"o\">.</span>user <span class=\"o\">=</span> AnonymousUser<span class=\"p\">()</span>\n\n        <span class=\"c1\"># Test my_view() as if it were deployed at /customer/details</span>\n        response <span class=\"o\">=</span> my_view<span class=\"p\">(</span>request<span class=\"p\">)</span>\n        <span class=\"c1\"># Use this syntax for class-based views.</span>\n        response <span class=\"o\">=</span> MyView<span class=\"o\">.</span>as_view<span class=\"p\">()(</span>request<span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>response<span class=\"o\">.</span>status_code<span class=\"p\">,</span> <span class=\"mi\">200</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"asyncrequestfactory\">\n<h3>AsyncRequestFactory<a class=\"heading-anchor\" href=\"#asyncrequestfactory\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\">RequestFactory</code> 创建 WSGI 类的请求。如果你想创建 ASGI 类的请求，包括有一个正确的 ASGI <code class=\"docutils literal notranslate\">scope</code>，你可以使用 <code class=\"docutils literal notranslate\">django.test.AsyncRequestFactory</code>。</p>\n<p>该类与 <code class=\"docutils literal notranslate\">RequestFactory</code> 直接 API 兼容，唯一的区别是它返回 <code class=\"docutils literal notranslate\">ASGIRequest</code> 实例，而不是 <code class=\"docutils literal notranslate\">WSGIRequest</code> 实例。它的所有方法仍然是可同步调用的。</p>\n</section>\n</section>\n<section id=\"testing-class-based-views\">\n<h2>测试基于类的视图<a class=\"heading-anchor\" href=\"#testing-class-based-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>为了在请求／响应周期之外测试基于类的视图，你必须确保它们配置正确，在实例化之后调用 <code class=\"xref py py-meth docutils literal notranslate\">setup()</code>。</p>\n<p>例如，假设基于类的视图如下：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">views.py</code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.views.generic</span> <span class=\"kn\">import</span> TemplateView\n\n\n<span class=\"k\">class</span> <span class=\"nc\">HomeView</span><span class=\"p\">(</span>TemplateView<span class=\"p\">):</span>\n    template_name <span class=\"o\">=</span> <span class=\"s1\">&#39;myapp/home.html&#39;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">get_context_data</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        kwargs<span class=\"p\">[</span><span class=\"s1\">&#39;environment&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Production&#39;</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>get_context_data<span class=\"p\">(</span><span class=\"o\">**</span>kwargs<span class=\"p\">)</span>\n</code></pre></figure>\n<p>你可以直接测试 <code class=\"docutils literal notranslate\">get_context_data()</code> 方法，首先实例化视图，然后向 <code class=\"docutils literal notranslate\">setup()</code> 传递一个 <code class=\"docutils literal notranslate\">request</code>，然后再进行测试代码。</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">tests.py</code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> RequestFactory<span class=\"p\">,</span> TestCase\n<span class=\"kn\">from</span> <span class=\"nn\">.views</span> <span class=\"kn\">import</span> HomeView\n\n\n<span class=\"k\">class</span> <span class=\"nc\">HomePageTest</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_environment_set_in_context</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        request <span class=\"o\">=</span> RequestFactory<span class=\"p\">()</span><span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/&#39;</span><span class=\"p\">)</span>\n        view <span class=\"o\">=</span> HomeView<span class=\"p\">()</span>\n        view<span class=\"o\">.</span>setup<span class=\"p\">(</span>request<span class=\"p\">)</span>\n\n        context <span class=\"o\">=</span> view<span class=\"o\">.</span>get_context_data<span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertIn<span class=\"p\">(</span><span class=\"s1\">&#39;environment&#39;</span><span class=\"p\">,</span> context<span class=\"p\">)</span>\n</code></pre></figure>\n</section>\n<section id=\"tests-and-multiple-host-names\">\n<span id=\"topics-testing-advanced-multiple-hosts\"></span><h2>测试与多主机名<a class=\"heading-anchor\" href=\"#tests-and-multiple-host-names\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p><a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-ALLOWED_HOSTS\"><code class=\"xref std std-setting docutils literal notranslate\">ALLOWED_HOSTS</code></a> 配置在运行测试时被验证。这允许测试客户端区分内部和外部 URL。</p>\n<p>支持多租户或根据请求的主机改变业务逻辑的项目，以及在测试中使用自定义主机名的项目，必须在 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-ALLOWED_HOSTS\"><code class=\"xref std std-setting docutils literal notranslate\">ALLOWED_HOSTS</code></a> 中包含这些主机。</p>\n<p>第一个选项是将主机添加到你的配置文件中。例如，docs.djangoproject.com 的测试套件包括以下内容：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> TestCase\n\n<span class=\"k\">class</span> <span class=\"nc\">SearchFormTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_empty_get</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        response <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/en/dev/search/&#39;</span><span class=\"p\">,</span> HTTP_HOST<span class=\"o\">=</span><span class=\"s1\">&#39;docs.djangoproject.dev:8000&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>response<span class=\"o\">.</span>status_code<span class=\"p\">,</span> <span class=\"mi\">200</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>同时配置文件包含项目支持的域列表：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>ALLOWED_HOSTS <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s1\">&#39;www.djangoproject.dev&#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;docs.djangoproject.dev&#39;</span><span class=\"p\">,</span>\n    <span class=\"o\">...</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>另一个选项是使用 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.override_settings\" title=\"django.test.override_settings\"><code class=\"xref py py-meth docutils literal notranslate\">override_settings()</code></a> 或 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#django.test.SimpleTestCase.modify_settings\" title=\"django.test.SimpleTestCase.modify_settings\"><code class=\"xref py py-attr docutils literal notranslate\">modify_settings()</code></a> 将所需的主机添加到 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-ALLOWED_HOSTS\"><code class=\"xref std std-setting docutils literal notranslate\">ALLOWED_HOSTS</code></a> 中。这个选项在不能打包自己配置文件的独立应用中可能比较好，或者对于域列表不是静态的项目（例如，多租户的子域）。例如，你可以为域 <code class=\"docutils literal notranslate\">http://otherserver/</code> 写一个测试，如下所示：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> TestCase<span class=\"p\">,</span> override_settings\n\n<span class=\"k\">class</span> <span class=\"nc\">MultiDomainTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"nd\">@override_settings</span><span class=\"p\">(</span>ALLOWED_HOSTS<span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;otherserver&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_other_domain</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        response <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;http://otherserver/foo/bar/&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>当运行测试时，禁用 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-ALLOWED_HOSTS\"><code class=\"xref std std-setting docutils literal notranslate\">ALLOWED_HOSTS</code></a> 检查（<code class=\"docutils literal notranslate\">ALLOWED_HOSTS = ['*']</code>），可以防止测试客户端在遵循重定向到外部 URL 时发出有用的错误信息。</p>\n</section>\n<section id=\"tests-and-multiple-databases\">\n<span id=\"topics-testing-advanced-multidb\"></span><h2>测试与多数据库<a class=\"heading-anchor\" href=\"#tests-and-multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"testing-primary-replica-configurations\">\n<span id=\"topics-testing-primaryreplica\"></span><h3>测试主／副配置<a class=\"heading-anchor\" href=\"#testing-primary-replica-configurations\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你使用主／副本（某些数据库称为主／从）复制来测试多数据库配置，那么这种创建测试数据库的策略会带来问题。当创建测试数据库时，不会有任何复制，因此，在主服务器上创建的数据在副本上看不到。</p>\n<p>为了弥补这一点，Django 允许你定义一个数据库是 <em>测试镜像</em>。考虑以下（简化的）数据库配置示例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>DATABASES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;default&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;ENGINE&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.db.backends.mysql&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;NAME&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;myproject&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;HOST&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;dbprimary&#39;</span><span class=\"p\">,</span>\n         <span class=\"c1\"># ... plus some other settings</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;replica&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;ENGINE&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.db.backends.mysql&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;NAME&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;myproject&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;HOST&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;dbreplica&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;TEST&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;MIRROR&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;default&#39;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n        <span class=\"c1\"># ... plus some other settings</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>在这个设置中，我们有两个数据库服务器。<code class=\"docutils literal notranslate\">dbprimary</code>，用数据库别名 <code class=\"docutils literal notranslate\">default</code> 描述，<code class=\"docutils literal notranslate\">dbreplica</code> 用别名 <code class=\"docutils literal notranslate\">replica</code> 描述。正如你所期望的那样，<code class=\"docutils literal notranslate\">dbreplica</code> 被数据库管理员配置为 <code class=\"docutils literal notranslate\">dbprimary</code> 的读副本，因此在正常活动中，对 <code class=\"docutils literal notranslate\">default</code> 的任何写入都会出现在 <code class=\"docutils literal notranslate\">replica</code> 上。</p>\n<p>如果 Django 创建了两个独立的测试数据库，就会破坏任何期望复制发生的测试。然而，<code class=\"docutils literal notranslate\">replica</code> 数据库已经被配置为测试镜像（使用 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-TEST_MIRROR\"><code class=\"xref std std-setting docutils literal notranslate\">MIRROR</code></a> 测试设置），表明在测试中，<code class=\"docutils literal notranslate\">replica</code> 应该被当作 <code class=\"docutils literal notranslate\">default</code> 的镜像。</p>\n<p>在配置测试环境时，<code class=\"docutils literal notranslate\">replica</code> 的测试版本将 <em>不会</em> 被创建。相反，与``replica`` 的连接将被重定向为指向 <code class=\"docutils literal notranslate\">default</code>。因此，对 <code class=\"docutils literal notranslate\">default</code> 的写入将出现在 <code class=\"docutils literal notranslate\">replica</code> 上——但这是因为它们实际上是同一个数据库，而不是因为两个数据库之间有数据复制。</p>\n</section>\n<section id=\"controlling-creation-order-for-test-databases\">\n<span id=\"topics-testing-creation-dependencies\"></span><h3>控制测试数据库的创建顺序<a class=\"heading-anchor\" href=\"#controlling-creation-order-for-test-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>默认情况下，Django 会假设所有的数据库都依赖于 <code class=\"docutils literal notranslate\">default</code> 数据库，因此总是先创建 <code class=\"docutils literal notranslate\">default</code> 数据库。但是，我们不保证测试配置中其他数据库的创建顺序。</p>\n<p>如果你的数据库配置需要特定的创建顺序，你可以使用 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-TEST_DEPENDENCIES\"><code class=\"xref std std-setting docutils literal notranslate\">DEPENDENCIES</code></a> 测试设置指定存在的依赖关系。考虑以下（简化的）数据库配置示例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>DATABASES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s1\">&#39;default&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"c1\"># ... db settings</span>\n        <span class=\"s1\">&#39;TEST&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;DEPENDENCIES&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;diamonds&#39;</span><span class=\"p\">],</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;diamonds&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"c1\"># ... db settings</span>\n        <span class=\"s1\">&#39;TEST&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;DEPENDENCIES&#39;</span><span class=\"p\">:</span> <span class=\"p\">[],</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;clubs&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"c1\"># ... db settings</span>\n        <span class=\"s1\">&#39;TEST&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;DEPENDENCIES&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;diamonds&#39;</span><span class=\"p\">],</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;spades&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"c1\"># ... db settings</span>\n        <span class=\"s1\">&#39;TEST&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;DEPENDENCIES&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;diamonds&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;hearts&#39;</span><span class=\"p\">],</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"s1\">&#39;hearts&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"c1\"># ... db settings</span>\n        <span class=\"s1\">&#39;TEST&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;DEPENDENCIES&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;diamonds&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;clubs&#39;</span><span class=\"p\">],</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>在这种配置下，将首先创建 <code class=\"docutils literal notranslate\">diamonds</code> 数据库，因为它是唯一没有依赖性的数据库。接下来将创建 <code class=\"docutils literal notranslate\">default</code> 和 <code class=\"docutils literal notranslate\">clubs</code> 数据库（尽管这两个数据库的创建顺序没有保证），然后是 <code class=\"docutils literal notranslate\">hearts</code>，最后是 <code class=\"docutils literal notranslate\">spades</code>。</p>\n<p>如果在 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-TEST_DEPENDENCIES\"><code class=\"xref std std-setting docutils literal notranslate\">DEPENDENCIES</code></a> 定义中存在任何循环依赖关系，将引发 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/exceptions/#django.core.exceptions.ImproperlyConfigured\" title=\"django.core.exceptions.ImproperlyConfigured\"><code class=\"xref py py-exc docutils literal notranslate\">ImproperlyConfigured</code></a> 异常。</p>\n</section>\n</section>\n<section id=\"advanced-features-of-transactiontestcase\">\n<h2><code class=\"docutils literal notranslate\">TransactionTestCase</code> 高级特性<a class=\"heading-anchor\" href=\"#advanced-features-of-transactiontestcase\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase.available_apps\">\n<span class=\"sig-prename descclassname\">TransactionTestCase.</span><span class=\"sig-name descname\">available_apps</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase.available_apps\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>这个属性是一个私有的 API。它可能会在未来被更改或删除，而不会有废弃期，例如为了适应应用程序加载的变化。</p>\n<p>它用来优化 Django 自己的测试套件，其中包含数百个模型，但不同应用中的模型之间没有关系。</p>\n</aside>\n<p>默认情况下，<code class=\"docutils literal notranslate\">available_apps</code> 是设置为 <code class=\"docutils literal notranslate\">None</code>。每次测试后，Django 都会调用 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/django-admin/#django-admin-flush\"><code class=\"xref std std-djadmin docutils literal notranslate\">flush</code></a> 来重置数据库状态。这将清空所有表，并发出 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\">post_migrate</code></a> 信号，为每个模型重新创建一个内容类型和四个权限。这个操作的花费和模型的数量成正比。</p>\n<p>将 <code class=\"docutils literal notranslate\">available_apps</code> 设置为应用程序列表会指示 Django 的行为就像只有这些应用程序的模型是可用的一样。<code class=\"docutils literal notranslate\">TransactionTestCase</code> 的行为改变如下：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/3.2/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\">post_migrate</code></a> 在每次测试前都会被触发，以创建可用应用中每个模型的内容类型和权限，以防它们缺失。</p></li>\n<li><p>每次测试后，Django 只清空可用应用中模型对应的表。但在数据库层面，清空表可能会级联到不可用应用中的相关模型。此外 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\">post_migrate</code></a> 并没有被触发，它将在选择了正确的应用集后，由下一个 <code class=\"docutils literal notranslate\">TransactionTestCase</code> 触发。</p></li>\n</ul>\n<p>由于数据库没有完全刷新，如果测试创建了没有包含在 <code class=\"docutils literal notranslate\">available_apps</code> 中的模型实例，它们就会泄漏，并可能导致不相关的测试失败。小心使用了会话的测试；默认的会话引擎将它们存储在数据库中。</p>\n<p>由于 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\">post_migrate</code></a> 在刷新数据库后并没有发出，所以它在一个 <code class=\"docutils literal notranslate\">TransactionTestCase</code> 后的状态与一个 <code class=\"docutils literal notranslate\">TestCase</code> 后的状态是不一样的：它丢失了由 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\">post_migrate</code></a> 监听器创建的行。考虑到 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/overview/#order-of-tests\"><span class=\"std std-ref\">执行测试的顺序</span></a>，这并不是一个问题，只要给定的测试套件中的所有 <code class=\"docutils literal notranslate\">TransactionTestCase</code> 都声明 <code class=\"docutils literal notranslate\">available_apps</code>，或者都没有声明。</p>\n<p><code class=\"docutils literal notranslate\">available_apps</code> 在 Django 自己的测试套件中是强制性的。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase.reset_sequences\">\n<span class=\"sig-prename descclassname\">TransactionTestCase.</span><span class=\"sig-name descname\">reset_sequences</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase.reset_sequences\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在 <code class=\"docutils literal notranslate\">TransactionTestCase</code> 上设置 <code class=\"docutils literal notranslate\">reset_sequences = True</code> 将确保队列在测试运行前总是被重置：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">TestsThatDependsOnPrimaryKeySequences</span><span class=\"p\">(</span>TransactionTestCase<span class=\"p\">):</span>\n    reset_sequences <span class=\"o\">=</span> <span class=\"kc\">True</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_animal_pk</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        lion <span class=\"o\">=</span> Animal<span class=\"o\">.</span>objects<span class=\"o\">.</span>create<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;lion&quot;</span><span class=\"p\">,</span> sound<span class=\"o\">=</span><span class=\"s2\">&quot;roar&quot;</span><span class=\"p\">)</span>\n        <span class=\"c1\"># lion.pk is guaranteed to always be 1</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>lion<span class=\"o\">.</span>pk<span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>除非明确测试主键序列号，否则建议你不要在测试中硬编码主键值。</p>\n<p>使用 <code class=\"docutils literal notranslate\">reset_sequences = True</code> 会减慢测试速度，因为主键重置是一个相对昂贵的数据库操作。</p>\n</dd></dl>\n\n</section>\n<section id=\"enforce-running-test-classes-sequentially\">\n<span id=\"topics-testing-enforce-run-sequentially\"></span><h2>强制按顺序运行测试类<a class=\"heading-anchor\" href=\"#enforce-running-test-classes-sequentially\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果你有一些测试类不能并行运行（例如，因为它们共享一个公共资源），你可以使用 <code class=\"docutils literal notranslate\">django.test.testcases.SerializeMixin</code> 来依次运行它们。这个 mixin 使用一个文件系统 <code class=\"docutils literal notranslate\">lockfile</code>。</p>\n<p>例如，你可以使用 <code class=\"docutils literal notranslate\">__file__</code> 来确定同一文件中所有继承自 <code class=\"docutils literal notranslate\">SerializeMixin</code> 的测试类将依次运行：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">import</span> <span class=\"nn\">os</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> TestCase\n<span class=\"kn\">from</span> <span class=\"nn\">django.test.testcases</span> <span class=\"kn\">import</span> SerializeMixin\n\n<span class=\"k\">class</span> <span class=\"nc\">ImageTestCaseMixin</span><span class=\"p\">(</span>SerializeMixin<span class=\"p\">):</span>\n    lockfile <span class=\"o\">=</span> <span class=\"vm\">__file__</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">setUp</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>filename <span class=\"o\">=</span> os<span class=\"o\">.</span>path<span class=\"o\">.</span>join<span class=\"p\">(</span>temp_storage_dir<span class=\"p\">,</span> <span class=\"s1\">&#39;my_file.png&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>file <span class=\"o\">=</span> create_file<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>filename<span class=\"p\">)</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">RemoveImageTests</span><span class=\"p\">(</span>ImageTestCaseMixin<span class=\"p\">,</span> TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_remove_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        os<span class=\"o\">.</span>remove<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>filename<span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertFalse<span class=\"p\">(</span>os<span class=\"o\">.</span>path<span class=\"o\">.</span>exists<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>filename<span class=\"p\">))</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">ResizeImageTests</span><span class=\"p\">(</span>ImageTestCaseMixin<span class=\"p\">,</span> TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_resize_image</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        resize_image<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>file<span class=\"p\">,</span> <span class=\"p\">(</span><span class=\"mi\">48</span><span class=\"p\">,</span> <span class=\"mi\">48</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>get_image_size<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>file<span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">48</span><span class=\"p\">,</span> <span class=\"mi\">48</span><span class=\"p\">))</span>\n</code></pre></div>\n</section>\n<section id=\"using-the-django-test-runner-to-test-reusable-applications\">\n<span id=\"testing-reusable-applications\"></span><h2>使用 Django 测试运行器测试可重用的应用程序<a class=\"heading-anchor\" href=\"#using-the-django-test-runner-to-test-reusable-applications\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果你正在编写一个 <a class=\"reference internal\" href=\"/zh-hans/3.2/intro/reusable-apps/\"><span class=\"doc\">可重用的应用程序</span></a>，你可能想使用 Django 测试运行器来运行你自己的测试套件，从而从 Django 测试基础设施中获益。</p>\n<p>常见的做法是在应用代码旁边有一个 <em>tests</em> 目录，结构如下：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>runtests<span class=\"o\">.</span>py\npolls<span class=\"o\">/</span>\n    <span class=\"fm\">__init__</span><span class=\"o\">.</span>py\n    models<span class=\"o\">.</span>py\n    <span class=\"o\">...</span>\ntests<span class=\"o\">/</span>\n    <span class=\"fm\">__init__</span><span class=\"o\">.</span>py\n    models<span class=\"o\">.</span>py\n    test_settings<span class=\"o\">.</span>py\n    tests<span class=\"o\">.</span>py\n</code></pre></div>\n<p>让我们看一下其中的两个文件：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">runtests.py</code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"ch\">#!/usr/bin/env python</span>\n<span class=\"kn\">import</span> <span class=\"nn\">os</span>\n<span class=\"kn\">import</span> <span class=\"nn\">sys</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">django</span>\n<span class=\"kn\">from</span> <span class=\"nn\">django.conf</span> <span class=\"kn\">import</span> settings\n<span class=\"kn\">from</span> <span class=\"nn\">django.test.utils</span> <span class=\"kn\">import</span> get_runner\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;__main__&quot;</span><span class=\"p\">:</span>\n    os<span class=\"o\">.</span>environ<span class=\"p\">[</span><span class=\"s1\">&#39;DJANGO_SETTINGS_MODULE&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;tests.test_settings&#39;</span>\n    django<span class=\"o\">.</span>setup<span class=\"p\">()</span>\n    TestRunner <span class=\"o\">=</span> get_runner<span class=\"p\">(</span>settings<span class=\"p\">)</span>\n    test_runner <span class=\"o\">=</span> TestRunner<span class=\"p\">()</span>\n    failures <span class=\"o\">=</span> test_runner<span class=\"o\">.</span>run_tests<span class=\"p\">([</span><span class=\"s2\">&quot;tests&quot;</span><span class=\"p\">])</span>\n    sys<span class=\"o\">.</span>exit<span class=\"p\">(</span><span class=\"nb\">bool</span><span class=\"p\">(</span>failures<span class=\"p\">))</span>\n</code></pre></figure>\n<p>这是运行测试套件的脚本。它设置 Django 环境，创建测试数据库并运行测试。</p>\n<p>为了清楚起见，这个例子只包含了使用 Django 测试运行器所需的最基本的内容。你可能会要添加命令行选项来控制详细程度，传递要运行的特定测试标签等。</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">tests/test_settings.py</code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code>SECRET_KEY <span class=\"o\">=</span> <span class=\"s1\">&#39;fake-key&#39;</span>\nINSTALLED_APPS <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;tests&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p>该文件包含运行应用程序测试所需的 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/settings/\"><span class=\"doc\">Django 配置</span></a>。</p>\n<p>再次，这是一个最小的例子；你的测试可能需要其他设置才能运行。</p>\n<p>由于 <em>tests</em> 包在运行测试时被包含在 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 中，你可以在它的 <code class=\"docutils literal notranslate\">models.py</code> 文件中定义只用于测试的模型。</p>\n</section>\n<section id=\"using-different-testing-frameworks\">\n<span id=\"other-testing-frameworks\"></span><h2>使用不同的测试框架<a class=\"heading-anchor\" href=\"#using-different-testing-frameworks\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>显然，<a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#module-unittest\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">unittest</code></a> 并不是唯一的 Python 测试框架。虽然 Django 并没有提供对替代框架的明确支持，但它确实提供了一种方法来调用为替代框架构建的测试，就像它们是正常的 Django 测试一样。</p>\n<p>当你运行 <code class=\"docutils literal notranslate\">./manage.py test</code> 时，Django 会查看 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-TEST_RUNNER\"><code class=\"xref std std-setting docutils literal notranslate\">TEST_RUNNER</code></a> 的配置来决定做什么。默认情况下， <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-TEST_RUNNER\"><code class=\"xref std std-setting docutils literal notranslate\">TEST_RUNNER</code></a> 指向 <code class=\"docutils literal notranslate\">'django.test.runner.DiscoverRunner'</code>。这个类定义了默认的 Django 测试行为。这个行为包括：</p>\n<ol class=\"arabic simple\">\n<li><p>进行全局性的测试前设置。</p></li>\n<li><p>在当前目录下的任何文件中寻找名称符合 <code class=\"docutils literal notranslate\">test*.py</code> 模式的测试。</p></li>\n<li><p>创建测试数据库。</p></li>\n<li><p>运行 <code class=\"docutils literal notranslate\">migrate</code> 将模型和初始数据安装到测试数据库中。</p></li>\n<li><p>运行 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/checks/\"><span class=\"doc\">系统检查</span></a>。</p></li>\n<li><p>运行找到的测试。</p></li>\n<li><p>销毁测试数据库。</p></li>\n<li><p>进行全局性的测试后拆解。</p></li>\n</ol>\n<p>如果你定义了自己的测试运行器类，并将 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-TEST_RUNNER\"><code class=\"xref std std-setting docutils literal notranslate\">TEST_RUNNER</code></a> 指向该类，那么每当你运行 <code class=\"docutils literal notranslate\">./manage.py test</code> 时，Django 就会执行你的测试运行器。通过这种方式，可以使用任何可以从 Python 代码中执行的测试框架，也可以修改 Django 测试执行过程来满足你的任何测试需求。</p>\n<section id=\"defining-a-test-runner\">\n<span id=\"topics-testing-test-runner\"></span><h3>定义测试运行器<a class=\"heading-anchor\" href=\"#defining-a-test-runner\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>测试运行器是一个类，他定义了 <code class=\"docutils literal notranslate\">run_tests()</code> 方法。Django 自带一个 <code class=\"docutils literal notranslate\">DiscoverRunner</code> 类，它定义了默认的 Django 测试行为。该类定义了进入点 <code class=\"docutils literal notranslate\">run_tests()</code>，再加上对 <code class=\"docutils literal notranslate\">run_tests()</code> 所使用的其他方法的选择，以此来建立，执行和拆除测试套件。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">DiscoverRunner</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">pattern<span class=\"o\">=</span><span class=\"default_value\">'test*.py'</span></em>, <em class=\"sig-param\">top_level<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">verbosity<span class=\"o\">=</span><span class=\"default_value\">1</span></em>, <em class=\"sig-param\">interactive<span class=\"o\">=</span><span class=\"default_value\">True</span></em>, <em class=\"sig-param\">failfast<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">keepdb<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">reverse<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">debug_mode<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">debug_sql<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">parallel<span class=\"o\">=</span><span class=\"default_value\">0</span></em>, <em class=\"sig-param\">tags<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">exclude_tags<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">test_name_patterns<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">pdb<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">buffer<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">enable_faulthandler<span class=\"o\">=</span><span class=\"default_value\">True</span></em>, <em class=\"sig-param\">timing<span class=\"o\">=</span><span class=\"default_value\">True</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p><code class=\"docutils literal notranslate\">DiscoverRunner</code> 将在任何符合 <code class=\"docutils literal notranslate\">pattern</code> 的文件中搜索测试。</p>\n<p><code class=\"docutils literal notranslate\">top_level</code> 可以用来指定包含顶级 Python 模块的目录。通常 Django 会自动计算出这个目录，所以不需要指定这个选项。如果指定了这个选项，一般来说，它应该是包含你的 <code class=\"docutils literal notranslate\">manage.py</code> 文件的目录。</p>\n<p><code class=\"docutils literal notranslate\">verbosity</code> 决定将打印到控制台的通知和调试信息的数量；<code class=\"docutils literal notranslate\">0</code> 为无输出，<code class=\"docutils literal notranslate\">1</code> 为正常输出，<code class=\"docutils literal notranslate\">2</code> 为详细输出。</p>\n<p>如果 <code class=\"docutils literal notranslate\">interactive</code> 是 <code class=\"docutils literal notranslate\">True</code>，则测试套件在执行测试套件时，有权限向用户请求指令。这种行为的一个例子是要求允许删除一个现有的测试数据库。如果 <code class=\"docutils literal notranslate\">interactive</code> 为 <code class=\"docutils literal notranslate\">False</code>，测试套件必须能够在没有任何人工干预的情况下运行。</p>\n<p>如果 <code class=\"docutils literal notranslate\">failfast</code> 为 <code class=\"docutils literal notranslate\">True</code>，测试套件将在检测到第一次测试失败后停止运行。</p>\n<p>如果 <code class=\"docutils literal notranslate\">keepdb</code> 为 <code class=\"docutils literal notranslate\">True</code>，测试套件将使用现有数据库，或在必要时创建一个数据库。如果 <code class=\"docutils literal notranslate\">False</code>，将创建一个新的数据库，并提示用户删除现有的数据库。</p>\n<p>如果 <code class=\"docutils literal notranslate\">reverse</code> 为 <code class=\"docutils literal notranslate\">True</code>，测试用例将以相反的顺序执行。这对于调试没有适当隔离和有副作用的测试可能很有用。使用这个选项时，<a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/overview/#order-of-tests\"><span class=\"std std-ref\">按测试类分组</span></a> 将被保留。</p>\n<p><code class=\"docutils literal notranslate\">debug_mode</code> 指定 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> 设置在运行测试之前应该设置成什么。</p>\n<p><code class=\"docutils literal notranslate\">parallel</code> 指定进程数。如果 <code class=\"docutils literal notranslate\">parallel</code> 大于 1，则测试套件会在 <code class=\"docutils literal notranslate\">parallel</code> （平行）进程下运行。如果测试用例比配置的进程少，Django 将会相应地减少进程数量。每一个进程都有自己的数据库。该选择要求使用第三方包 <code class=\"docutils literal notranslate\">tblib</code> 来正确地显示回溯信息。</p>\n<p><code class=\"docutils literal notranslate\">tags</code> 用于指定一系列 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#topics-tagging-tests\"><span class=\"std std-ref\">测试标签</span></a>。可以与 <code class=\"docutils literal notranslate\">exclude_tags</code> 结合使用。</p>\n<p><code class=\"docutils literal notranslate\">exclude_tags</code> 用于指定一系列 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/tools/#topics-tagging-tests\"><span class=\"std std-ref\">排除测试标签</span></a>。可以与 <code class=\"docutils literal notranslate\">tags</code> 结合使用。</p>\n<p>如果 <code class=\"docutils literal notranslate\">debug_sql</code> 为 <code class=\"docutils literal notranslate\">True</code>，失败的测试用例会输出 SQL 查询记录到 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/logging/#django-db-logger\"><span class=\"std std-ref\">django.db.backends logger</span></a> 以及回溯。如果 <code class=\"docutils literal notranslate\">verbosity</code> 是 <code class=\"docutils literal notranslate\">2</code>，那么所有测试中的查询都会输出。</p>\n<p><code class=\"docutils literal notranslate\">test_name_patterns</code> 可以用来指定一套模式，通过名称过滤测试方法和类。</p>\n<p>如果 <code class=\"docutils literal notranslate\">pdb</code> 为 <code class=\"docutils literal notranslate\">True</code>，则每次测试错误或失败时都会产生一个调试器（<code class=\"docutils literal notranslate\">pdb</code> 或 <code class=\"docutils literal notranslate\">ipdb</code>）。</p>\n<p>如果 <code class=\"docutils literal notranslate\">buffer</code> 为 <code class=\"docutils literal notranslate\">True</code>，通过测试的输出将被丢弃。</p>\n<p>如果 <code class=\"docutils literal notranslate\">enable_faulthandler</code> 是 <code class=\"docutils literal notranslate\">True</code>，那么 <a class=\"reference external\" href=\"https://docs.python.org/3/library/faulthandler.html#module-faulthandler\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">faulthandler</code></a> 将被启用。</p>\n<p>如果 <code class=\"docutils literal notranslate\">timing</code> 是 <code class=\"docutils literal notranslate\">True</code>，将显示测试时间，包括数据库设置和总运行时间。</p>\n<p>Django 可能会不时地通过添加新的参数来扩展测试运行器的功能。<code class=\"docutils literal notranslate\">**kwargs</code> 声明允许这种扩展。如果你将 <code class=\"docutils literal notranslate\">DiscoverRunner</code> 子类化，或者编写你自己的测试运行器，确保它接受 <code class=\"docutils literal notranslate\">**kwargs</code>。</p>\n<p>你的测试运行器也可以定义额外的命令行选项。创建或覆盖一个 <code class=\"docutils literal notranslate\">add_arguments(cls, parser)</code> 类方法，并通过在该方法中调用 <code class=\"docutils literal notranslate\">parser.add_argument()</code> 来添加自定义参数，这样 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/django-admin/#django-admin-test\"><code class=\"xref std std-djadmin docutils literal notranslate\">test</code></a> 命令就可以使用这些参数。</p>\n<aside class=\"version-note version-added\" data-version=\"3.1\" role=\"note\">\n<p class=\"version-note-title\">New in Django 3.1</p><p>增加了 <code class=\"docutils literal notranslate\">buffer</code> 参数。</p>\n</aside>\n<aside class=\"version-note version-added\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">New in Django 3.2</p><p>增加了 <code class=\"docutils literal notranslate\">enable_faulthandler</code> 和 <code class=\"docutils literal notranslate\">timing</code> 参数。</p>\n</aside>\n</dd></dl>\n\n<section id=\"attributes\">\n<h4>属性<a class=\"heading-anchor\" href=\"#attributes\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.test_suite\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">test_suite</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.test_suite\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>用于构建测试套件的类。默认情况下，它被设置为 <code class=\"docutils literal notranslate\">unittest.TestSuite</code>。如果你想实现不同的测试收集逻辑，可以重写这个类。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.test_runner\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">test_runner</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.test_runner\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>这是低级测试运行器的类，用于执行各个测试和格式化结果。默认情况下，它被设置为 <code class=\"docutils literal notranslate\">unittest.TextTestRunner</code>。尽管在命名习惯上有不幸的相似之处，但这与 <code class=\"docutils literal notranslate\">DiscoverRunner</code> 不是同一类型的类，后者涵盖了更广泛的职责。你可以覆盖这个属性来修改测试运行和报告的方式。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.test_loader\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">test_loader</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.test_loader\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>这是一个加载测试的类，无论是从 TestCases 还是模块或其他方面加载测试，并将它们捆绑成测试套件供运行者执行。默认情况下，它被设置为 <code class=\"docutils literal notranslate\">unittest.defaultTestLoader</code>。如果你的测试要以不寻常的方式加载，你可以重写这个属性。</p>\n</dd></dl>\n\n</section>\n<section id=\"methods\">\n<h4>方法<a class=\"heading-anchor\" href=\"#methods\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.run_tests\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">run_tests</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">test_labels</em>, <em class=\"sig-param\">extra_tests<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.run_tests\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>运行测试套件。</p>\n<p><code class=\"docutils literal notranslate\">test_labels</code> 允许你指定要运行的测试，并支持多种格式（参见 <a class=\"reference internal\" href=\"#django.test.runner.DiscoverRunner.build_suite\" title=\"django.test.runner.DiscoverRunner.build_suite\"><code class=\"xref py py-meth docutils literal notranslate\">DiscoverRunner.build_suite()</code></a> 获取支持的格式列表）。</p>\n<p><code class=\"docutils literal notranslate\">extra_tests</code> 是一个额外的 <code class=\"docutils literal notranslate\">TestCase</code> 实例列表，用于添加到测试运行器执行的套件中。这些额外的测试是在 <code class=\"docutils literal notranslate\">test_labels</code> 中列出的模块中发现的测试之外运行的。</p>\n<p>这个方法应该返回失败的测试次数。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.add_arguments\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">add_arguments</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">parser</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.add_arguments\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>重写这个类方法来添加 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/django-admin/#django-admin-test\"><code class=\"xref std std-djadmin docutils literal notranslate\">test</code></a> 管理命令接受的自定义参数。参见 <a class=\"reference external\" href=\"https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">argparse.ArgumentParser.add_argument()</code></a> 了解关于向解析器添加参数的详细信息。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.setup_test_environment\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">setup_test_environment</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.setup_test_environment\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>通过调用 <a class=\"reference internal\" href=\"#django.test.utils.setup_test_environment\" title=\"django.test.utils.setup_test_environment\"><code class=\"xref py py-func docutils literal notranslate\">setup_test_environment()</code></a> 和设置 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> 为 <code class=\"docutils literal notranslate\">self.debug_mode</code> （默认为 <code class=\"docutils literal notranslate\">False</code>）来设置测试环境。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.build_suite\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">build_suite</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">test_labels<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">extra_tests<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.build_suite\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>构建一个与提供的测试标签相匹配的测试套件。</p>\n<p><code class=\"docutils literal notranslate\">test_labels</code> 是描述要运行的测试的字符串列表。测试标签可以采取以下四种形式之一：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">path.to.test_module.TestCase.test_method</code>——在测试用例中运行一个测试方法。</p></li>\n<li><p><code class=\"docutils literal notranslate\">path.to.test_module.TestCase</code>——运行测试用例中的所有测试方法。</p></li>\n<li><p><code class=\"docutils literal notranslate\">path.to.module</code>——搜索并运行命名的 Python 包或模块中的所有测试。</p></li>\n<li><p><code class=\"docutils literal notranslate\">path/to/directory</code>——搜索并运行指定目录下的所有测试。</p></li>\n</ul>\n<p>如果 <code class=\"docutils literal notranslate\">test_labels</code> 的值为 <code class=\"docutils literal notranslate\">None</code>，测试运行器将在当前目录下所有文件中搜索名称符合 <code class=\"docutils literal notranslate\">pattern</code> 的测试（见上文）。</p>\n<p><code class=\"docutils literal notranslate\">extra_tests</code> 是一个额外的 <code class=\"docutils literal notranslate\">TestCase</code> 实例列表，用于添加到测试运行器执行的套件中。这些额外的测试是在 <code class=\"docutils literal notranslate\">test_labels</code> 中列出的模块中发现的测试之外运行的。</p>\n<p>返回一个准备运行的 <code class=\"docutils literal notranslate\">TestSuite</code> 实例。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.setup_databases\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">setup_databases</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.setup_databases\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>通过调用 <a class=\"reference internal\" href=\"#django.test.utils.setup_databases\" title=\"django.test.utils.setup_databases\"><code class=\"xref py py-func docutils literal notranslate\">setup_databases()</code></a> 创建测试数据库。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.run_checks\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">run_checks</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">databases</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.run_checks\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在测试的 <code class=\"docutils literal notranslate\">databases</code> 上运行 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/checks/\"><span class=\"doc\">系统检查</span></a>。</p>\n<aside class=\"version-note version-added\" data-version=\"3.1\" role=\"note\">\n<p class=\"version-note-title\">New in Django 3.1</p><p>增加了 <code class=\"docutils literal notranslate\">databases</code> 参数。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.run_suite\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">run_suite</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">suite</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.run_suite\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>运行测试套件。</p>\n<p>返回运行测试套件所产生的结果。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.get_test_runner_kwargs\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">get_test_runner_kwargs</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.get_test_runner_kwargs\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回实例化 <code class=\"docutils literal notranslate\">DiscoverRunner.test_runner</code> 的关键字参数。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.teardown_databases\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">teardown_databases</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">old_config</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.teardown_databases\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>通过调用 <code class=\"xref py py-func docutils literal notranslate\">trapdown_databases()</code> 来销毁测试数据库，恢复测试前的条件。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.teardown_test_environment\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">teardown_test_environment</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.teardown_test_environment\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>恢复测试前的环境。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.runner.DiscoverRunner.suite_result\">\n<span class=\"sig-prename descclassname\">DiscoverRunner.</span><span class=\"sig-name descname\">suite_result</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">suite</em>, <em class=\"sig-param\">result</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.runner.DiscoverRunner.suite_result\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>计算并返回一个返回码，基于测试套件和测试套件返回的结果。</p>\n</dd></dl>\n\n</section>\n</section>\n<section id=\"testing-utilities\">\n<h3>测试工具集<a class=\"heading-anchor\" href=\"#testing-utilities\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<section id=\"module-django.test.utils\">\n<span id=\"django-test-utils\"></span><h4><code class=\"docutils literal notranslate\">django.test.utils</code><a class=\"heading-anchor\" href=\"#module-django.test.utils\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>为了帮助创建自己的测试运行器，Django 在 <code class=\"docutils literal notranslate\">django.test.utils</code> 模块中提供了一些实用的方法。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.utils.setup_test_environment\">\n<span class=\"sig-name descname\">setup_test_environment</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">debug<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.utils.setup_test_environment\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>执行全局性的测试前设置，如为模板渲染系统安装仪器，设置虚拟的电子邮件发件箱。</p>\n<p>如果 <code class=\"docutils literal notranslate\">debug</code> 不是 <code class=\"docutils literal notranslate\">None</code>，则 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DEBUG\"><code class=\"xref std std-setting docutils literal notranslate\">DEBUG</code></a> 配置更新为其值。</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.utils.teardown_test_environment\">\n<span class=\"sig-name descname\">teardown_test_environment</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.utils.teardown_test_environment\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>进行全局性的测试后拆解，如从模板系统中删除仪器设备，恢复正常的邮件服务。</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.utils.setup_databases\">\n<span class=\"sig-name descname\">setup_databases</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">verbosity</em>, <em class=\"sig-param\">interactive</em>, <em class=\"sig-param\"><span class=\"keyword-only-separator o\"><abbr title=\"Keyword-only parameters separator (PEP 3102)\">*</abbr></span></em>, <em class=\"sig-param\">time_keeper<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">keepdb<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">debug_sql<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">parallel<span class=\"o\">=</span><span class=\"default_value\">0</span></em>, <em class=\"sig-param\">aliases<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.utils.setup_databases\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>创建测试数据库。</p>\n<p>返回一个数据结构，该结构提供了足够的细节来撤销已做的更改。这些数据将在测试结束后提供给 <a class=\"reference internal\" href=\"#django.test.utils.teardown_databases\" title=\"django.test.utils.teardown_databases\"><code class=\"xref py py-func docutils literal notranslate\">teardown_databases()</code></a> 函数。</p>\n<p><code class=\"docutils literal notranslate\">aliases</code> 参数决定应该为哪些 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 别名设置测试数据库。如果没有提供这个参数，则默认为所有的 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 别名。</p>\n<aside class=\"version-note version-changed\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 3.2</p><p>增加了 <code class=\"docutils literal notranslate\">time_keeper</code> 关键字，并且所有的 kwargs 都变成了仅关键字参数。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.utils.teardown_databases\">\n<span class=\"sig-name descname\">teardown_databases</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">old_config</em>, <em class=\"sig-param\">parallel<span class=\"o\">=</span><span class=\"default_value\">0</span></em>, <em class=\"sig-param\">keepdb<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.utils.teardown_databases\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>销毁测试数据库，恢复测试前的条件。</p>\n<p><code class=\"docutils literal notranslate\">old_config</code> 是一个数据结构，定义了数据库配置中需要撤销的变化。它是 <a class=\"reference internal\" href=\"#django.test.utils.setup_databases\" title=\"django.test.utils.setup_databases\"><code class=\"xref py py-meth docutils literal notranslate\">setup_databases()</code></a> 方法的返回值。</p>\n</dd></dl>\n\n</section>\n<section id=\"django-db-connection-creation\">\n<h4><code class=\"docutils literal notranslate\">django.db.connection.creation</code><a class=\"heading-anchor\" href=\"#django-db-connection-creation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>数据库后台的创建模块还提供了一些在测试过程中有用的实用程序。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.db.connection.creation.create_test_db\">\n<span class=\"sig-name descname\">create_test_db</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">verbosity<span class=\"o\">=</span><span class=\"default_value\">1</span></em>, <em class=\"sig-param\">autoclobber<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">serialize<span class=\"o\">=</span><span class=\"default_value\">True</span></em>, <em class=\"sig-param\">keepdb<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.db.connection.creation.create_test_db\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>创建一个新的测试数据库并对其运行 <code class=\"docutils literal notranslate\">migrate</code>。</p>\n<p><code class=\"docutils literal notranslate\">verbosity</code> 与 <code class=\"docutils literal notranslate\">run_tests()</code> 中的行为相同。</p>\n<p><code class=\"docutils literal notranslate\">autoclobber</code> 描述了在发现与测试数据库同名的数据库时将发生的行为。</p>\n<ul class=\"simple\">\n<li><p>如果 <code class=\"docutils literal notranslate\">autoclobber</code> 为 <code class=\"docutils literal notranslate\">False</code>，将要求用户批准销毁现有数据库。如果用户不同意，则调用 <code class=\"docutils literal notranslate\">sys.exit</code>。</p></li>\n<li><p>如果 autoclobber 为 <code class=\"docutils literal notranslate\">True</code>，数据库将在不与用户协商的情况下被销毁。</p></li>\n</ul>\n<p><code class=\"docutils literal notranslate\">serialize</code> 决定 Django 是否在运行测试之前将数据库序列化为内存中的 JSON 字符串（如果没有事务，用于在测试之间恢复数据库状态）。如果你没有使用 <a class=\"reference internal\" href=\"/zh-hans/3.2/topics/testing/overview/#test-case-serialized-rollback\"><span class=\"std std-ref\">serialized_rollback=True</span></a> 的测试类，你可以将其设置为 <code class=\"docutils literal notranslate\">False</code> 以加快创建时间。</p>\n<p>如果你使用的是默认的测试运行器，你可以通过 <code class=\"xref std std-setting docutils literal notranslate\">TEST</code> 条目来控制。</p>\n<p><code class=\"docutils literal notranslate\">keepdb</code> 决定测试运行是否应使用现有数据库，还是创建一个新的数据库。如果 True`，则使用现有的数据库，如果不存在，则创建新的数据库。如果 <code class=\"docutils literal notranslate\">False</code>，则创建一个新的数据库，并提示用户删除现有的数据库（如果存在）。</p>\n<p>返回其创建的测试数据库的名称。</p>\n<p><code class=\"docutils literal notranslate\">create_test_db()</code> 的副作用是修改 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 中的 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-NAME\"><code class=\"xref std std-setting docutils literal notranslate\">NAME</code></a> 的值，使其与测试数据库的名称相匹配。</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.db.connection.creation.destroy_test_db\">\n<span class=\"sig-name descname\">destroy_test_db</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">old_database_name</em>, <em class=\"sig-param\">verbosity<span class=\"o\">=</span><span class=\"default_value\">1</span></em>, <em class=\"sig-param\">keepdb<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.db.connection.creation.destroy_test_db\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>销毁名称为 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 中 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-NAME\"><code class=\"xref std std-setting docutils literal notranslate\">NAME</code></a> 值的数据库，并将 <a class=\"reference internal\" href=\"/zh-hans/3.2/ref/settings/#std-setting-NAME\"><code class=\"xref std std-setting docutils literal notranslate\">NAME</code></a> 设置为 <code class=\"docutils literal notranslate\">old_database_name</code> 值。</p>\n<p><code class=\"docutils literal notranslate\">verbosity</code>  参数和测试类 <a class=\"reference internal\" href=\"#django.test.runner.DiscoverRunner\" title=\"django.test.runner.DiscoverRunner\"><code class=\"xref py py-class docutils literal notranslate\">DiscoverRunner</code></a> 的行为一样。</p>\n<p>如果 <code class=\"docutils literal notranslate\">keepdb</code> 的参数为 <code class=\"docutils literal notranslate\">True</code> ，数据库连接会被关闭，但是数据库不会被销毁。</p>\n</dd></dl>\n\n</section>\n</section>\n</section>\n<section id=\"integration-with-coverage-py\">\n<span id=\"topics-testing-code-coverage\"></span><h2>集成 <code class=\"docutils literal notranslate\">coverage.py</code><a class=\"heading-anchor\" href=\"#integration-with-coverage-py\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>代码覆盖度表示有多少源代码被测试了。它表明了代码的哪些部分被测试用例覆盖，哪些没有。这是测试应用很重要的部分，所以强烈推荐检查测试用例的覆盖度。</p>\n<p>Django很容易集成 coverage.py ，一个测试Python程序的代码覆盖度的工具。首先， <a class=\"reference external\" href=\"https://coverage.readthedocs.io/\">安装 coverage.py</a> 。然后， 在包含 <code class=\"docutils literal notranslate\">manage.py</code> 的项目文件夹下运行。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>coverage run <span class=\"o\">--</span>source<span class=\"o\">=</span><span class=\"s1\">&#39;.&#39;</span> manage<span class=\"o\">.</span>py test myapp\n</code></pre></div>\n<p>这样就会跑你的测试用例然后收集你的项目中被执行的文件的覆盖率数据。你可以通过输入如下命令来输出这个结果的报告。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>coverage report\n</code></pre></div>\n<p>请注意一些Django代码会在运行期间被执行，但是因为在上一条命令中没有 <code class=\"docutils literal notranslate\">source</code> 选项所以在这里没有列出。</p>\n<p>关于类似于输出详细内容的HTML列举的没有覆盖区域的选项，请查阅 <a class=\"reference external\" href=\"https://coverage.readthedocs.io/\">coverage.py</a> 的文档。</p>\n</section>","rootId":"advanced-testing-topics","toc":[{"title":"请求工厂","anchor":"the-request-factory","children":[{"title":"例如","anchor":"example","children":[]},{"title":"AsyncRequestFactory","anchor":"asyncrequestfactory","children":[]}]},{"title":"测试基于类的视图","anchor":"testing-class-based-views","children":[]},{"title":"测试与多主机名","anchor":"tests-and-multiple-host-names","children":[]},{"title":"测试与多数据库","anchor":"tests-and-multiple-databases","children":[{"title":"测试主／副配置","anchor":"testing-primary-replica-configurations","children":[]},{"title":"控制测试数据库的创建顺序","anchor":"controlling-creation-order-for-test-databases","children":[]}]},{"title":"TransactionTestCase 高级特性","anchor":"advanced-features-of-transactiontestcase","children":[]},{"title":"强制按顺序运行测试类","anchor":"enforce-running-test-classes-sequentially","children":[]},{"title":"使用 Django 测试运行器测试可重用的应用程序","anchor":"using-the-django-test-runner-to-test-reusable-applications","children":[]},{"title":"使用不同的测试框架","anchor":"using-different-testing-frameworks","children":[{"title":"定义测试运行器","anchor":"defining-a-test-runner","children":[{"title":"属性","anchor":"attributes","children":[]},{"title":"方法","anchor":"methods","children":[]}]},{"title":"测试工具集","anchor":"testing-utilities","children":[{"title":"django.test.utils","anchor":"module-django.test.utils","children":[]},{"title":"django.db.connection.creation","anchor":"django-db-connection-creation","children":[]}]}]},{"title":"集成 coverage.py","anchor":"integration-with-coverage-py","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/3.2/topics/"},{"docname":"topics/testing/index","title":"Django 中的测试","url":"/zh-hans/3.2/topics/testing/"}],"prev":{"docname":"topics/testing/tools","title":"测试工具","url":"/zh-hans/3.2/topics/testing/tools/"},"next":{"docname":"topics/auth/index","title":"Django中的用户认证","url":"/zh-hans/3.2/topics/auth/"},"formats":{"html":"/zh-hans/3.2/topics/testing/advanced/","markdown":"/zh-hans/3.2/topics/testing/advanced.md","json":"/zh-hans/3.2/topics/testing/advanced.json"},"source":"https://github.com/django/django/blob/stable/3.2.x/docs/topics/testing/advanced.txt","official":"https://docs.djangoproject.com/zh-hans/3.2/topics/testing/advanced/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}