{"title":"测试工具","version":"4.0","locale":"zh-hans","docname":"topics/testing/tools","url":"/zh-hans/4.0/topics/testing/tools/","canonical":"https://djangodocs.dev/zh-hans/4.0/topics/testing/tools/","summary":"Django 提供了一小组在编写测试时会派上用场的工具。The test client is a Python class that acts as a dummy web browser, allowing you to test your views and…","html":"<h1>测试工具<a class=\"heading-anchor\" href=\"#testing-tools\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 提供了一小组在编写测试时会派上用场的工具。</p>\n<section id=\"the-test-client\">\n<span id=\"test-client\"></span><h2>测试客户端<a class=\"heading-anchor\" href=\"#the-test-client\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The test client is a Python class that acts as a dummy web browser, allowing\nyou to test your views and interact with your Django-powered application\nprogrammatically.</p>\n<p>你可以使用测试客户端执行以下操作：</p>\n<ul class=\"simple\">\n<li><p>模拟 URL 上的 GET 和 POST 请求并观察响应——从低级 HTTP（结果头和状态码）到页面内容，应有尽有。</p></li>\n<li><p>查看重定向链（如果有的话），并检查每个步骤的 URL 和状态码。</p></li>\n<li><p>测试给定的请求是否由给定的包含某些值以及模板上下文的 Django 模板渲染。</p></li>\n</ul>\n<p>请注意，测试客户端并不是要取代 <a class=\"reference external\" href=\"https://www.selenium.dev/\">Selenium</a> 或其他“浏览器内”框架。Django 的测试客户端有不同的侧重点。简而言之：</p>\n<ul class=\"simple\">\n<li><p>使用 Django 的测试客户端来确定要渲染的模板正确，并且模板已传递了正确的上下文数据。</p></li>\n<li><p>Use in-browser frameworks like <a class=\"reference external\" href=\"https://www.selenium.dev/\">Selenium</a> to test <em>rendered</em> HTML and the\n<em>behavior</em> of web pages, namely JavaScript functionality. Django also\nprovides special support for those frameworks; see the section on\n<a class=\"reference internal\" href=\"#django.test.LiveServerTestCase\" title=\"django.test.LiveServerTestCase\"><code class=\"xref py py-class docutils literal notranslate\">LiveServerTestCase</code></a> for more details.</p></li>\n</ul>\n<p>一个全面的测试套件应该使用这两种测试类型的组合。</p>\n<section id=\"overview-and-a-quick-example\">\n<h3>概述和一个简单的例子<a class=\"heading-anchor\" href=\"#overview-and-a-quick-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>To use the test client, instantiate <code class=\"docutils literal notranslate\">django.test.Client</code> and retrieve\nweb pages:</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=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> Client\n<span class=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response <span class=\"o\">=</span> c<span class=\"o\">.</span>post<span class=\"p\">(</span><span class=\"s1\">&#39;/login/&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;username&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;john&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;password&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;smith&#39;</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response<span class=\"o\">.</span>status_code\n<span class=\"go\">200</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response <span class=\"o\">=</span> c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customer/details/&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response<span class=\"o\">.</span>content\n<span class=\"go\">b&#39;&lt;!DOCTYPE html...&#39;</span>\n</code></pre></div>\n<p>如本例所示，你可以从 Python 交互式解释器的会话中实例化 <code class=\"docutils literal notranslate\">Client</code>。</p>\n<p>请注意测试客户端如何工作的一些重要事项：</p>\n<ul>\n<li><p>The test client does <em>not</em> require the web server to be running. In fact,\nit will run just fine with no web server running at all! That's because\nit avoids the overhead of HTTP and deals directly with the Django\nframework. This helps make the unit tests run quickly.</p></li>\n<li><p>检索页面时，请记住指定 URL 的 <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><span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/login/&#39;</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><span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;https://www.example.com/login/&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>The test client is not capable of retrieving web pages that are not\npowered by your Django project. If you need to retrieve other web pages,\nuse a Python standard library module such as <a class=\"reference external\" href=\"https://docs.python.org/3/library/urllib.html#module-urllib\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">urllib</code></a>.</p>\n</li>\n<li><p>为了解析 URL，测试客户端使用你的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-ROOT_URLCONF\"><code class=\"xref std std-setting docutils literal notranslate\">ROOT_URLCONF</code></a> 配置指向的任何 URLconf。</p></li>\n<li><p>虽然上面的例子可以在 Python 交互式解释器中工作，但是测试客户端的一些功能，尤其是与模板相关的功能，只有在 <em>测试运行时</em> 才可以使用。</p>\n<p>原因是 Django 的测试运行器为了确定哪个模板被给定的视图加载，执行了一点黑魔法。这个黑魔法（本质上是内存中 Django 模板系统的补丁）只发生在测试运行期间。</p>\n</li>\n<li><p>默认情况下，测试客户端将禁用站点执行的任何 CSRF 检查。</p>\n<p>如果出于某种原因，你 <em>想</em> 让测试客户端执行 CSRF 检查，则可以创建强制执行 CSRF 检查的测试客户端实例。为此，请在构建客户端时传递 <code class=\"docutils literal notranslate\">enforce_csrf_checks</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=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> Client\n<span class=\"gp\">&gt;&gt;&gt; </span>csrf_client <span class=\"o\">=</span> Client<span class=\"p\">(</span>enforce_csrf_checks<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n</code></pre></div>\n</li>\n</ul>\n</section>\n<section id=\"making-requests\">\n<h3>发出请求<a class=\"heading-anchor\" href=\"#making-requests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>使用 <code class=\"docutils literal notranslate\">django.test.Client</code> 类发出请求。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">Client</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">enforce_csrf_checks<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">json_encoder<span class=\"o\">=</span><span class=\"default_value\">DjangoJSONEncoder</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>defaults</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>它在构造时不需要任何参数。然而，你可以使用关键字参数来指定一些默认头信息。例如，这将在每个请求中发送一个 <code class=\"docutils literal notranslate\">User-Agent</code> HTTP 头：</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">(</span>HTTP_USER_AGENT<span class=\"o\">=</span><span class=\"s1\">&#39;Mozilla/5.0&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>传递给 <a class=\"reference internal\" href=\"#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=\"#django.test.Client.post\" title=\"django.test.Client.post\"><code class=\"xref py py-meth docutils literal notranslate\">post()</code></a> 等方法的 <code class=\"docutils literal notranslate\">extra</code> 关键字参数的值，优先于传递给类构造函数的默认值。</p>\n<p><code class=\"docutils literal notranslate\">enforce_csrf_checks</code> 参数可用于测试 CSRF 保护（见上文）。</p>\n<p><code class=\"docutils literal notranslate\">json_encoder</code> 参数允许为 <a class=\"reference internal\" href=\"#django.test.Client.post\" title=\"django.test.Client.post\"><code class=\"xref py py-meth docutils literal notranslate\">post()</code></a> 中描述的 JSON 序列化设置一个自定义 JSON 编码器。</p>\n<p><code class=\"docutils literal notranslate\">raise_request_exception</code> 参数允许控制是否在请求过程中引出的异常也应该在测试中引出。默认值为 <code class=\"docutils literal notranslate\">True</code>。</p>\n<p>一旦有了 <code class=\"docutils literal notranslate\">Client</code> 实例，就可以调用以下任何一种方法：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.get\">\n<span class=\"sig-name descname\">get</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.get\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>对提供的 <code class=\"docutils literal notranslate\">path</code> 上发出 GET 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象，如下所述。</p>\n<p><code class=\"docutils literal notranslate\">data</code> 字典中的键值对用于创建 GET 数据有效载荷。例如：</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customers/details/&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;age&#39;</span><span class=\"p\">:</span> <span class=\"mi\">7</span><span class=\"p\">})</span>\n</code></pre></div>\n<p>......将产生等效的 GET 请求：</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>/customers/details/?name=fred&amp;age=7\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">extra</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customers/details/&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;age&#39;</span><span class=\"p\">:</span> <span class=\"mi\">7</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>      HTTP_ACCEPT<span class=\"o\">=</span><span class=\"s1\">&#39;application/json&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>......会将 HTTP 头 <code class=\"docutils literal notranslate\">HTTP_ACCEPT</code> 发送到 detail 视图，这是测试使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpRequest.accepts\" title=\"django.http.HttpRequest.accepts\"><code class=\"xref py py-meth docutils literal notranslate\">django.http.HttpRequest.accepts()</code></a> 方法的代码路径的好方法。</p>\n<aside class=\"admonition-cgi-specification admonition\" role=\"note\">\n<p class=\"admonition-title\">CGI 规范</p>\n<p>通过 <code class=\"docutils literal notranslate\">**extra</code> 发送的头信息应遵循 <a class=\"reference external\" href=\"https://www.w3.org/CGI/\">CGI</a> 规范。例如，在浏览器向服务器发送的 HTTP 请求中，模拟不同的“Host”头，应以 <code class=\"docutils literal notranslate\">HTTP_HOST</code> 的形式发送。</p>\n</aside>\n<p>如果你已经有了 URL 编码形式的 GET 参数，你可以使用该编码代替使用数据参数。例如，之前的 GET 请求也可以改成：</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customers/details/?name=fred&amp;age=7&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你提供的 URL 同时包含编码的 GET 数据和数据参数，数据参数将优先。</p>\n<p>如果将 <code class=\"docutils literal notranslate\">follow</code> 设置为 <code class=\"docutils literal notranslate\">True</code>，客户端将遵循所有重定向，并且将在响应对象中设置 <code class=\"docutils literal notranslate\">redirect_chain</code> 属性，该属性是包含中间 URL 和状态码的元组。</p>\n<p>如果你有一个 URL <code class=\"docutils literal notranslate\">/redirect_me/</code>，重定向到 <code class=\"docutils literal notranslate\">/next/</code>，再重定向到 <code class=\"docutils literal notranslate\">/final/</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=\"gp\">&gt;&gt;&gt; </span>response <span class=\"o\">=</span> c<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/redirect_me/&#39;</span><span class=\"p\">,</span> follow<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response<span class=\"o\">.</span>redirect_chain\n<span class=\"go\">[(&#39;http://testserver/next/&#39;, 302), (&#39;http://testserver/final/&#39;, 302)]</span>\n</code></pre></div>\n<p>如果你把 <code class=\"docutils literal notranslate\">secure</code> 设置为 <code class=\"docutils literal notranslate\">True</code>，则客户端将模拟 HTTPS 请求。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.post\">\n<span class=\"sig-name descname\">post</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">content_type<span class=\"o\">=</span><span class=\"default_value\">MULTIPART_CONTENT</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.post\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 POST 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象，如下所述。</p>\n<p><code class=\"docutils literal notranslate\">data</code> 字典中的键值对用于提交 POST 数据。例如：</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>post<span class=\"p\">(</span><span class=\"s1\">&#39;/login/&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;passwd&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;secret&#39;</span><span class=\"p\">})</span>\n</code></pre></div>\n<p>......将产生对这个 URL 的 POST 请求：</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=\"o\">/</span>login<span class=\"o\">/</span>\n</code></pre></div>\n<p>......具有此 POST 数据：</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>name<span class=\"o\">=</span>fred<span class=\"o\">&amp;</span>passwd<span class=\"o\">=</span>secret\n</code></pre></div>\n<p>如果你提供 <em class=\"mimetype\">application/json</em> 为 <code class=\"docutils literal notranslate\">content_type</code>，则如果 <code class=\"docutils literal notranslate\">data</code> 是一个字典、列表或元组时，使用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#json.dumps\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">json.dumps()</code></a> 进行序列化。序列化默认是通过 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/serialization/#django.core.serializers.json.DjangoJSONEncoder\" title=\"django.core.serializers.json.DjangoJSONEncoder\"><code class=\"xref py py-class docutils literal notranslate\">DjangoJSONEncoder</code></a>，可以通过为 <a class=\"reference internal\" href=\"#django.test.Client\" title=\"django.test.Client\"><code class=\"xref py py-class docutils literal notranslate\">Client</code></a> 提供 <code class=\"docutils literal notranslate\">json_encoder</code> 参数覆盖。这个序列化也会发生在 <a class=\"reference internal\" href=\"#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=\"#django.test.Client.patch\" title=\"django.test.Client.patch\"><code class=\"xref py py-meth docutils literal notranslate\">patch()</code></a> 和 <a class=\"reference internal\" href=\"#django.test.Client.delete\" title=\"django.test.Client.delete\"><code class=\"xref py py-meth docutils literal notranslate\">delete()</code></a> 请求中。</p>\n<p>如果你要提供任何其他的 <code class=\"docutils literal notranslate\">content_type</code> （例如 <em class=\"mimetype\">text/xml</em> 用于 XML 有效载荷），使用HTTP <code class=\"docutils literal notranslate\">Content-Type</code> 头中的 <code class=\"docutils literal notranslate\">content_type</code>，<code class=\"docutils literal notranslate\">data</code> 的内容在 POST 请求中按原样发送。</p>\n<p>如果你没有为 <code class=\"docutils literal notranslate\">content_type</code> 提供一个值，<code class=\"docutils literal notranslate\">data</code> 中的值将以 <em class=\"mimetype\">multipart/form-data</em> 的内容类型进行传输。在这种情况下，<code class=\"docutils literal notranslate\">data</code> 中的键值对将被编码为多部分消息，并用于创建 POST 数据有效载荷。</p>\n<p>要为一个给定的键提交多个值——例如，要指定 <code class=\"docutils literal notranslate\">&lt;select multiple&gt;</code> 的选择——为所需键提供一个列表或元组的值。例如，这个 <code class=\"docutils literal notranslate\">data</code> 的值将为名为 <code class=\"docutils literal notranslate\">choices</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=\"p\">{</span><span class=\"s1\">&#39;choices&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;a&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;b&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;d&#39;</span><span class=\"p\">)}</span>\n</code></pre></div>\n<p>提交文件是一种特殊情况。要 POST 一个文件，你只需要提供文件字段名作为键，以及你想上传的文件的文件句柄作为值。例如：</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;wishlist.doc&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> fp<span class=\"p\">:</span>\n<span class=\"gp\">... </span>    c<span class=\"o\">.</span>post<span class=\"p\">(</span><span class=\"s1\">&#39;/customers/wishes/&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;attachment&#39;</span><span class=\"p\">:</span> fp<span class=\"p\">})</span>\n</code></pre></div>\n<p>（这里的 <code class=\"docutils literal notranslate\">attachment</code> 名称无关紧要；可以使用你的文件处理代码期望的任何名称。）</p>\n<p>你也可以提供任何类似于文件的对象（例如 <a class=\"reference external\" href=\"https://docs.python.org/3/library/io.html#io.StringIO\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">StringIO</code></a> 或 <a class=\"reference external\" href=\"https://docs.python.org/3/library/io.html#io.BytesIO\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">BytesIO</code></a>）作为文件句柄。如果你要上传到 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/models/fields/#django.db.models.ImageField\" title=\"django.db.models.ImageField\"><code class=\"xref py py-class docutils literal notranslate\">ImageField</code></a>，这个对象需要一个可以通过 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/validators/#django.core.validators.validate_image_file_extension\" title=\"django.core.validators.validate_image_file_extension\"><code class=\"xref py py-data docutils literal notranslate\">validate_image_file_extension</code></a> 验证器的 <code class=\"docutils literal notranslate\">name</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=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">io</span> <span class=\"kn\">import</span> BytesIO\n<span class=\"gp\">&gt;&gt;&gt; </span>img <span class=\"o\">=</span> BytesIO<span class=\"p\">(</span><span class=\"sa\">b</span><span class=\"s1\">&#39;mybinarydata&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>img<span class=\"o\">.</span>name <span class=\"o\">=</span> <span class=\"s1\">&#39;myimage.jpg&#39;</span>\n</code></pre></div>\n<p>请注意，如果你想在多次调用 <code class=\"docutils literal notranslate\">post()</code> 时使用同一个文件句柄，那么你需要在两次调用之间手动重置文件指针。最简单的方法是在向 <code class=\"docutils literal notranslate\">post()</code> 提供文件后手动关闭文件，如上所示。</p>\n<p>你还应确保文件的打开方式允许数据被读取。如果你的文件包含二进制数据，如图像，这意味着你需要以 <code class=\"docutils literal notranslate\">rb</code> （读取二进制）模式打开文件。</p>\n<p><code class=\"docutils literal notranslate\">extra</code> 参数的作用与 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a> 相同。</p>\n<p>如果你用 POST 请求的 URL 包含编码参数，这些参数将在 request.GET 数据中提供。例如，如果你要请求：</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=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>post<span class=\"p\">(</span><span class=\"s1\">&#39;/login/?visitor=true&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;passwd&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;secret&#39;</span><span class=\"p\">})</span>\n</code></pre></div>\n<p>......处理这个请求的视图可以询问 request.POST 来检索用户名和密码，也可以询问 request.GET 来确定该用户是否是访客。</p>\n<p>如果将 <code class=\"docutils literal notranslate\">follow</code> 设置为 <code class=\"docutils literal notranslate\">True</code>，客户端将遵循所有重定向，并且将在响应对象中设置 <code class=\"docutils literal notranslate\">redirect_chain</code> 属性，该属性是包含中间 URL 和状态码的元组。</p>\n<p>如果你把 <code class=\"docutils literal notranslate\">secure</code> 设置为 <code class=\"docutils literal notranslate\">True</code>，则客户端将模拟 HTTPS 请求。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.head\">\n<span class=\"sig-name descname\">head</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.head\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 HEAD 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象。这个方法的工作原理和 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a>  一样，包括 <code class=\"docutils literal notranslate\">follow</code>、<code class=\"docutils literal notranslate\">secure</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数，只是它不返回消息主体。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.options\">\n<span class=\"sig-name descname\">options</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">content_type<span class=\"o\">=</span><span class=\"default_value\">'application/octet-stream'</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.options\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 OPTIONS 请求并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象。用于测试 RESTful 接口。</p>\n<p>当提供 <code class=\"docutils literal notranslate\">data</code> 时，它将被用作请求主体并且 <code class=\"docutils literal notranslate\">Content-Type</code> 头被设置为 <code class=\"docutils literal notranslate\">content_type</code>。</p>\n<p><code class=\"docutils literal notranslate\">follow</code>、 <code class=\"docutils literal notranslate\">secure</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数的作用与 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a> 相同。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.put\">\n<span class=\"sig-name descname\">put</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">content_type<span class=\"o\">=</span><span class=\"default_value\">'application/octet-stream'</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.put\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 PUT 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象。用于测试 RESTful 接口。</p>\n<p>当提供 <code class=\"docutils literal notranslate\">data</code> 时，它将被用作请求主体并且 <code class=\"docutils literal notranslate\">Content-Type</code> 头被设置为 <code class=\"docutils literal notranslate\">content_type</code>。</p>\n<p><code class=\"docutils literal notranslate\">follow</code>、 <code class=\"docutils literal notranslate\">secure</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数的作用与 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a> 相同。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.patch\">\n<span class=\"sig-name descname\">patch</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">content_type<span class=\"o\">=</span><span class=\"default_value\">'application/octet-stream'</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.patch\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 PATCH 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象。用于测试 RESTful 接口。</p>\n<p><code class=\"docutils literal notranslate\">follow</code>、 <code class=\"docutils literal notranslate\">secure</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数的作用与 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a> 相同。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.delete\">\n<span class=\"sig-name descname\">delete</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">data<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">content_type<span class=\"o\">=</span><span class=\"default_value\">'application/octet-stream'</span></em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.delete\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 DELETE 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象。用于测试 RESTful 接口。</p>\n<p>当提供 <code class=\"docutils literal notranslate\">data</code> 时，它将被用作请求主体并且 <code class=\"docutils literal notranslate\">Content-Type</code> 头被设置为 <code class=\"docutils literal notranslate\">content_type</code>。</p>\n<p><code class=\"docutils literal notranslate\">follow</code>、 <code class=\"docutils literal notranslate\">secure</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数的作用与 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a> 相同。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.trace\">\n<span class=\"sig-name descname\">trace</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">path</em>, <em class=\"sig-param\">follow<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\">secure<span class=\"o\">=</span><span class=\"default_value\">False</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>extra</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.trace\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在提供的 <code class=\"docutils literal notranslate\">path</code> 上发出一个 TRACE 请求，并返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象。用于模拟诊断探针。</p>\n<p>与其他请求方法不同，为了符合 <span class=\"target\" id=\"index-6\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc7231.html#section-4.3.8\"><strong>RFC 7231 Section 4.3.8</strong></a> 的要求，不提供 <code class=\"docutils literal notranslate\">data</code> 作为关键字参数，该 RFC 要求跟踪请求不能有主体。</p>\n<p><code class=\"docutils literal notranslate\">follow</code>、 <code class=\"docutils literal notranslate\">secure</code> 和 <code class=\"docutils literal notranslate\">extra</code> 参数的作用与 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a> 相同。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.login\">\n<span class=\"sig-name descname\">login</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">**</span>credentials</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.login\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果你的网站使用了 Django 的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/\"><span class=\"doc\">认证系统</span></a>，并且你需要处理登录用户的问题，你可以使用测试客户端的 <code class=\"docutils literal notranslate\">login()</code> 方法来模拟用户登录网站的效果。</p>\n<p>调用此方法后，测试客户端将拥有通过任何可能构成视图一部分的基于登录的测试所需的所有 cookie 和会话数据。</p>\n<p><code class=\"docutils literal notranslate\">credentials</code> 参数的格式取决于你使用的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/customizing/#authentication-backends\"><span class=\"std std-ref\">认证后端</span></a> （这是由你的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\">AUTHENTICATION_BACKENDS</code></a> 配置）。如果你使用的是 Django 提供的标准认证后端（<code class=\"docutils literal notranslate\">ModelBackend</code>），<code class=\"docutils literal notranslate\">credentials</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>login<span class=\"p\">(</span>username<span class=\"o\">=</span><span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"s1\">&#39;secret&#39;</span><span class=\"p\">)</span>\n\n<span class=\"go\"># Now you can access a view that&#39;s only available to logged-in users.</span>\n</code></pre></div>\n<p>如果你使用的是不同的认证后端，这个方法可能需要不同的凭证。它需要你的后端 <code class=\"docutils literal notranslate\">authenticate()</code> 方法所需要的任何凭证。</p>\n<p>如果凭证被接受且登录成功，则 <code class=\"docutils literal notranslate\">login()</code> 返回 <code class=\"docutils literal notranslate\">True</code>。</p>\n<p>最后，在使用这个方法之前，你需要记得创建用户账户。正如我们上面所解释的，测试运行器是使用测试数据库执行的，默认情况下，数据库中不包含用户。因此，在生产站点上有效的用户账户在测试条件下将无法工作。你需要创建用户作为测试套件的一部分--无论是手动创建（使用 Django 模型 API）还是使用测试夹具。记住，如果你想让你的测试用户有一个密码，你不能直接通过设置密码属性来设置用户的密码——你必须使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/auth/#django.contrib.auth.models.User.set_password\" title=\"django.contrib.auth.models.User.set_password\"><code class=\"xref py py-meth docutils literal notranslate\">set_password()</code></a> 函数来存储一个正确的哈希密码。或者，你可以使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/auth/#django.contrib.auth.models.UserManager.create_user\" title=\"django.contrib.auth.models.UserManager.create_user\"><code class=\"xref py py-meth docutils literal notranslate\">create_user()</code></a> 辅助方法来创建一个具有正确哈希密码的新用户。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.force_login\">\n<span class=\"sig-name descname\">force_login</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">user</em>, <em class=\"sig-param\">backend<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.force_login\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果你的网站使用了 Django 的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/\"><span class=\"doc\">认证系统</span></a>，你可以使用 <code class=\"docutils literal notranslate\">force_login()</code> 方法来模拟用户登录网站的效果。当测试需要用户登录，而用户如何登录的细节并不重要时，可以使用这个方法代替 <a class=\"reference internal\" href=\"#django.test.Client.login\" title=\"django.test.Client.login\"><code class=\"xref py py-meth docutils literal notranslate\">login()</code></a>。</p>\n<p>与 <code class=\"docutils literal notranslate\">login()</code> 不同的是，这个方法跳过了认证和验证步骤：不活跃的用户（<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">is_active=False</code></a>）被允许登录，并且不需要提供用户凭证。</p>\n<p>用户的 <code class=\"docutils literal notranslate\">backend</code> 属性将被设置为 <code class=\"docutils literal notranslate\">backend</code> 参数的值（应该是一个点分隔 Python 路径字符串），如果没有提供值，则设置为 <code class=\"docutils literal notranslate\">settings.AUTHENTICATION_BACKENDS[0]</code>。<a class=\"reference internal\" href=\"#django.test.Client.login\" title=\"django.test.Client.login\"><code class=\"xref py py-meth docutils literal notranslate\">login()</code></a> 调用的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/default/#django.contrib.auth.authenticate\" title=\"django.contrib.auth.authenticate\"><code class=\"xref py py-func docutils literal notranslate\">authenticate()</code></a> 函数通常会对用户进行注释。</p>\n<p>这个方法比 <code class=\"docutils literal notranslate\">login()</code> 快，因为它绕过了昂贵的密码散列算法。另外，你也可以通过 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/testing/overview/#speeding-up-tests-auth-hashers\"><span class=\"std std-ref\">在测试时使用较弱的哈希算法</span></a> 来加快 <code class=\"docutils literal notranslate\">login()</code> 速度。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.logout\">\n<span class=\"sig-name descname\">logout</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.Client.logout\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果你的网站使用了 Django 的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/auth/\"><span class=\"doc\">认证系统</span></a>，<code class=\"docutils literal notranslate\">logout()</code> 方法可以用来模拟用户注销网站的效果。</p>\n<p>调用此方法后，测试客户端的所有 cookie 和会话数据都会被清除为默认值。随后的请求将看起来来自一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/auth/#django.contrib.auth.models.AnonymousUser\" title=\"django.contrib.auth.models.AnonymousUser\"><code class=\"xref py py-class docutils literal notranslate\">AnonymousUser</code></a>。</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"testing-responses\">\n<h3>测试响应<a class=\"heading-anchor\" href=\"#testing-responses\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><code class=\"docutils literal notranslate\">get()</code> 和 <code class=\"docutils literal notranslate\">post()</code> 方法都会返回一个 <code class=\"docutils literal notranslate\">Response</code> 对象，这个 <code class=\"docutils literal notranslate\">Response</code> 对象与 Django 视图返回的 <code class=\"docutils literal notranslate\">HttpResponse</code> 对象是 <em>不</em> 一样的；测试响应对象有一些额外的数据，对测试代码验证很有用。</p>\n<p>具体来说，<code class=\"docutils literal notranslate\">Response</code> 对象具有以下属性：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">Response</span><a class=\"heading-anchor\" href=\"#django.test.Response\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.client\">\n<span class=\"sig-name descname\">client</span><a class=\"heading-anchor\" href=\"#django.test.Response.client\"><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 attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.content\">\n<span class=\"sig-name descname\">content</span><a class=\"heading-anchor\" href=\"#django.test.Response.content\"><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 attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.context\">\n<span class=\"sig-name descname\">context</span><a class=\"heading-anchor\" href=\"#django.test.Response.context\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>模板 <code class=\"docutils literal notranslate\">Context</code> 实例，用于渲染产生响应内容的模板。</p>\n<p>如果渲染的页面使用了多个模板，那么 <code class=\"docutils literal notranslate\">context</code> 将是一个按渲染顺序排列的 <code class=\"docutils literal notranslate\">Context</code> 对象列表。</p>\n<p>无论在渲染过程中使用了多少模板，你都可以使用 <code class=\"docutils literal notranslate\">[]</code> 操作符来检索上下文值。例如，上下文变量 <code class=\"docutils literal notranslate\">name</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=\"gp\">&gt;&gt;&gt; </span>response <span class=\"o\">=</span> client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/foo/&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response<span class=\"o\">.</span>context<span class=\"p\">[</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">]</span>\n<span class=\"go\">&#39;Arthur&#39;</span>\n</code></pre></div>\n<aside class=\"admonition-not-using-django-templates admonition\" role=\"note\">\n<p class=\"admonition-title\">没有使用 Django 模板？</p>\n<p>这个属性只有在使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/templates/#django.template.backends.django.DjangoTemplates\" title=\"django.template.backends.django.DjangoTemplates\"><code class=\"xref py py-class docutils literal notranslate\">DjangoTemplates</code></a> 后端时才会被填充。如果你正在使用其他模板引擎，在带有该属性的响应上，<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/template-response/#django.template.response.SimpleTemplateResponse.context_data\" title=\"django.template.response.SimpleTemplateResponse.context_data\"><code class=\"xref py py-attr docutils literal notranslate\">context_data</code></a> 可能是一个合适的选择。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.exc_info\">\n<span class=\"sig-name descname\">exc_info</span><a class=\"heading-anchor\" href=\"#django.test.Response.exc_info\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>一个由三个值组成的元组，它提供了关于在视图期间发生的未处理异常（如果有）的信息。</p>\n<p>值是（type，value，traceback），与 Python 的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/sys.html#sys.exc_info\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">sys.exc_info()</code></a> 返回的值相同。它们的含义是：</p>\n<ul class=\"simple\">\n<li><p><em>type</em>：异常的类型。</p></li>\n<li><p><em>value</em>：异常的实例。</p></li>\n<li><p><em>traceback</em>：一个追溯对象，在最初发生异常的地方封装了调用堆栈。</p></li>\n</ul>\n<p>如果没有发生异常，那么 <code class=\"docutils literal notranslate\">exc_info</code> 将是 <code class=\"docutils literal notranslate\">None</code>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.json\">\n<span class=\"sig-name descname\">json</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.Response.json\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>解析为 JSON 的响应主体。额外的关键字参数传递给 <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#json.loads\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">json.loads()</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><span class=\"gp\">&gt;&gt;&gt; </span>response <span class=\"o\">=</span> client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/foo/&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>response<span class=\"o\">.</span>json<span class=\"p\">()[</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">]</span>\n<span class=\"go\">&#39;Arthur&#39;</span>\n</code></pre></div>\n<p>如果 <code class=\"docutils literal notranslate\">Content-Type</code> 头不是 <code class=\"docutils literal notranslate\">&quot;application/json&quot;</code>，那么在试图解析响应时将会出现一个 <a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#ValueError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\">ValueError</code></a>。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.request\">\n<span class=\"sig-name descname\">request</span><a class=\"heading-anchor\" href=\"#django.test.Response.request\"><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 attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.wsgi_request\">\n<span class=\"sig-name descname\">wsgi_request</span><a class=\"heading-anchor\" href=\"#django.test.Response.wsgi_request\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>由生成响应的测试处理程序生成的 <code class=\"docutils literal notranslate\">WSGIRequest</code> 实例。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.status_code\">\n<span class=\"sig-name descname\">status_code</span><a class=\"heading-anchor\" href=\"#django.test.Response.status_code\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>整数形式的响应 HTTP 状态。关于定义代码的完整列表，查看 <a class=\"reference external\" href=\"https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml\">IANA status code registry</a>.</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.templates\">\n<span class=\"sig-name descname\">templates</span><a class=\"heading-anchor\" href=\"#django.test.Response.templates\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>用于渲染最终内容的 <code class=\"docutils literal notranslate\">Template</code> 实例列表，按渲染顺序排列。对于列表中的每个模板，如果模板是从文件中加载的，则使用 <code class=\"docutils literal notranslate\">template.name</code> 获得模板的文件名。（名字是一个字符串，如 <code class=\"docutils literal notranslate\">'admin/index.html'</code>。）</p>\n<aside class=\"admonition-not-using-django-templates admonition\" role=\"note\">\n<p class=\"admonition-title\">没有使用 Django 模板？</p>\n<p>这个属性只有在使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/templates/#django.template.backends.django.DjangoTemplates\" title=\"django.template.backends.django.DjangoTemplates\"><code class=\"xref py py-class docutils literal notranslate\">DjangoTemplates</code></a> 后端时才会被填充。如果你使用的是其他模板引擎，并且你只需要渲染所用模板的名称，那么 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/template-response/#django.template.response.SimpleTemplateResponse.template_name\" title=\"django.template.response.SimpleTemplateResponse.template_name\"><code class=\"xref py py-attr docutils literal notranslate\">template_name</code></a> 可能是一个合适的选择。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Response.resolver_match\">\n<span class=\"sig-name descname\">resolver_match</span><a class=\"heading-anchor\" href=\"#django.test.Response.resolver_match\"><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/4.0/ref/urlresolvers/#django.urls.ResolverMatch\" title=\"django.urls.ResolverMatch\"><code class=\"xref py py-class docutils literal notranslate\">ResolverMatch</code></a> 的实例。你可以使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/urlresolvers/#django.urls.ResolverMatch.func\" title=\"django.urls.ResolverMatch.func\"><code class=\"xref py py-attr docutils literal notranslate\">func</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><span class=\"c1\"># my_view here is a function based view</span>\n<span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>response<span class=\"o\">.</span>resolver_match<span class=\"o\">.</span>func<span class=\"p\">,</span> my_view<span class=\"p\">)</span>\n\n<span class=\"c1\"># class-based views need to be compared by name, as the functions</span>\n<span class=\"c1\"># generated by as_view() won&#39;t be equal</span>\n<span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>response<span class=\"o\">.</span>resolver_match<span class=\"o\">.</span>func<span class=\"o\">.</span><span class=\"vm\">__name__</span><span class=\"p\">,</span> MyView<span class=\"o\">.</span>as_view<span class=\"p\">()</span><span class=\"o\">.</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果找不到给定的 URL，访问这个属性会引发一个 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/exceptions/#django.urls.Resolver404\" title=\"django.urls.Resolver404\"><code class=\"xref py py-exc docutils literal notranslate\">Resolver404</code></a> 异常。</p>\n</dd></dl>\n\n</dd></dl>\n\n<p>和普通的响应一样，你也可以通过 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse.headers\" title=\"django.http.HttpResponse.headers\"><code class=\"xref py py-attr docutils literal notranslate\">HttpResponse.headers</code></a> 访问头信息。例如，你可以使用 <code class=\"docutils literal notranslate\">response.headers['Content-Type']</code> 来确定一个响应的内容类型。</p>\n</section>\n<section id=\"exceptions\">\n<h3>例外<a class=\"heading-anchor\" href=\"#exceptions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你把测试客户端指向一个会引发异常的视图，并且 <code class=\"docutils literal notranslate\">Client.raise_request_exception</code> 是 <code class=\"docutils literal notranslate\">True</code>，那么这个异常将在测试用例中可见。然后你可以使用标准的 <code class=\"docutils literal notranslate\">try ... except</code> 块或 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertRaises\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">assertRaises()</code></a> 来测试异常。</p>\n<p>测试客户端看不到的异常只有 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/http/views/#django.http.Http404\" title=\"django.http.Http404\"><code class=\"xref py py-class docutils literal notranslate\">Http404</code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/exceptions/#django.core.exceptions.PermissionDenied\" title=\"django.core.exceptions.PermissionDenied\"><code class=\"xref py py-class docutils literal notranslate\">PermissionDenied</code></a>、<a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#SystemExit\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\">SystemExit</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/exceptions/#django.core.exceptions.SuspiciousOperation\" title=\"django.core.exceptions.SuspiciousOperation\"><code class=\"xref py py-class docutils literal notranslate\">SuspiciousOperation</code></a>。Django 在内部捕获这些异常，并将其转换为相应的 HTTP 响应代码。在这些情况下，你可以在测试中检查 <code class=\"docutils literal notranslate\">response.status_code</code>。</p>\n<p>如果 <code class=\"docutils literal notranslate\">Client.raise_request_exception</code> 为 <code class=\"docutils literal notranslate\">False</code>，测试客户端将返回一个 500 的响应，就像返回给浏览器一样。响应有属性 <a class=\"reference internal\" href=\"#django.test.Response.exc_info\" title=\"django.test.Response.exc_info\"><code class=\"xref py py-attr docutils literal notranslate\">exc_info</code></a> 来提供关于未处理的异常的信息。</p>\n</section>\n<section id=\"persistent-state\">\n<h3>持久状态<a class=\"heading-anchor\" href=\"#persistent-state\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>测试客户端是有状态的。如果一个响应返回一个 cookie，那么这个 cookie 将被存储在测试客户端，并与所有后续的 <code class=\"docutils literal notranslate\">get()</code> 和 <code class=\"docutils literal notranslate\">post()</code> 请求一起发送。</p>\n<p>不遵循这些 cookie 的过期策略。如果你希望 cookie 过期，请手动删除它或创建一个新的 <code class=\"docutils literal notranslate\">Client</code> 实例（这将有效地删除所有 cookie）。</p>\n<p>测试客户端有两个属性，存储持久化的状态信息。你可以作为测试条件的一部分来访问这些属性。</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.cookies\">\n<span class=\"sig-prename descclassname\">Client.</span><span class=\"sig-name descname\">cookies</span><a class=\"heading-anchor\" href=\"#django.test.Client.cookies\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>一个 Python <a class=\"reference external\" href=\"https://docs.python.org/3/library/http.cookies.html#http.cookies.SimpleCookie\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">SimpleCookie</code></a> 对象，包含所有客户端 cookie 的当前值。更多信息请参见 <a class=\"reference external\" href=\"https://docs.python.org/3/library/http.cookies.html#module-http.cookies\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">http.cookies</code></a> 模块的文档。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.Client.session\">\n<span class=\"sig-prename descclassname\">Client.</span><span class=\"sig-name descname\">session</span><a class=\"heading-anchor\" href=\"#django.test.Client.session\"><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/4.0/topics/http/sessions/\"><span class=\"doc\">会话文档</span></a>。</p>\n<p>要修改会话然后保存，必须先将其存储在一个变量中（因为每次访问该属性时都会创建一个新的 <code class=\"docutils literal notranslate\">SessionStore</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\">def</span> <span class=\"nf\">test_something</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    session <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>client<span class=\"o\">.</span>session\n    session<span class=\"p\">[</span><span class=\"s1\">&#39;somekey&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;test&#39;</span>\n    session<span class=\"o\">.</span>save<span class=\"p\">()</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n<section id=\"setting-the-language\">\n<h3>设置语言<a class=\"heading-anchor\" href=\"#setting-the-language\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在测试支持国际化和本地化的应用程序时，你可能想为测试客户端请求设置语言。这样做的方法取决于 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/middleware/#django.middleware.locale.LocaleMiddleware\" title=\"django.middleware.locale.LocaleMiddleware\"><code class=\"xref py py-class docutils literal notranslate\">LocaleMiddleware</code></a> 是否启用。</p>\n<p>如果启用了中间件，可以通过创建一个名为 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-LANGUAGE_COOKIE_NAME\"><code class=\"xref std std-setting docutils literal notranslate\">LANGUAGE_COOKIE_NAME</code></a> 的 cookie 来设置语言，其值为语言代码：。</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.conf</span> <span class=\"kn\">import</span> settings\n\n<span class=\"k\">def</span> <span class=\"nf\">test_language_using_cookie</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"bp\">self</span><span class=\"o\">.</span>client<span class=\"o\">.</span>cookies<span class=\"o\">.</span>load<span class=\"p\">({</span>settings<span class=\"o\">.</span>LANGUAGE_COOKIE_NAME<span class=\"p\">:</span> <span class=\"s1\">&#39;fr&#39;</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;/&#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>content<span class=\"p\">,</span> <span class=\"sa\">b</span><span class=\"s2\">&quot;Bienvenue sur mon site.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>或在请求中加入 <code class=\"docutils literal notranslate\">Accept-Language</code> HTTP 头：</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\">def</span> <span class=\"nf\">test_language_using_header</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;/&#39;</span><span class=\"p\">,</span> HTTP_ACCEPT_LANGUAGE<span class=\"o\">=</span><span class=\"s1\">&#39;fr&#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>content<span class=\"p\">,</span> <span class=\"sa\">b</span><span class=\"s2\">&quot;Bienvenue sur mon site.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>更多细节请参考 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/i18n/translation/#how-django-discovers-language-preference\"><span class=\"std std-ref\">Django 如何发现语言偏好</span></a>。</p>\n<p>如果中间件没有启用，可以使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/utils/#django.utils.translation.override\" title=\"django.utils.translation.override\"><code class=\"xref py py-func docutils literal notranslate\">translation.override()</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><span class=\"kn\">from</span> <span class=\"nn\">django.utils</span> <span class=\"kn\">import</span> translation\n\n<span class=\"k\">def</span> <span class=\"nf\">test_language_using_override</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"k\">with</span> translation<span class=\"o\">.</span>override<span class=\"p\">(</span><span class=\"s1\">&#39;fr&#39;</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;/&#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>content<span class=\"p\">,</span> <span class=\"sa\">b</span><span class=\"s2\">&quot;Bienvenue sur mon site.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>更多细节见 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/i18n/translation/#explicitly-setting-the-active-language\"><span class=\"std std-ref\">显式设置语言</span></a>。</p>\n</section>\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\">import</span> <span class=\"nn\">unittest</span>\n<span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> Client\n\n<span class=\"k\">class</span> <span class=\"nc\">SimpleTest</span><span class=\"p\">(</span>unittest<span class=\"o\">.</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 a client.</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>client <span class=\"o\">=</span> Client<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\"># Issue a GET request.</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;/customer/details/&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Check that the response is 200 OK.</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\n        <span class=\"c1\"># Check that the rendered context contains 5 customers.</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span>response<span class=\"o\">.</span>context<span class=\"p\">[</span><span class=\"s1\">&#39;customers&#39;</span><span class=\"p\">]),</span> <span class=\"mi\">5</span><span class=\"p\">)</span>\n</code></pre></div>\n<aside class=\"admonition admonition-seealso\" role=\"note\">\n<p class=\"admonition-title\">See also</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/4.0/topics/testing/advanced/#django.test.RequestFactory\" title=\"django.test.RequestFactory\"><code class=\"xref py py-class docutils literal notranslate\">django.test.RequestFactory</code></a></p>\n</aside>\n</section>\n</section>\n<section id=\"provided-test-case-classes\">\n<span id=\"django-testcase-subclasses\"></span><h2>提供的测试用例类<a class=\"heading-anchor\" href=\"#provided-test-case-classes\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>一般的 Python 单元测试类都会扩展一个基类 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">unittest.TestCase</code></a>。Django 提供了这个基类的一些扩展。</p>\n<figure class=\"align-default\" id=\"id4\">\n<span id=\"testcase-hierarchy-diagram\"></span><a class=\"reference internal image-reference\" href=\"../../../../../../_images/django_unittest_classes_hierarchy.svg\"><img alt=\"Hierarchy of Django unit testing classes (TestCase subclasses)\" src=\"/zh-hans/4.0/_images/django_unittest_classes_hierarchy.svg\" style=\"width: 508px; height: 328px;\" />\n</a>\n<figcaption>\n<p><span class=\"caption-text\">Django 单元测试类的层次结构</span><a class=\"heading-anchor\" href=\"#id4\"><span class=\"visually-hidden\">Link to this image</span><span aria-hidden=\"true\">#</span></a></p>\n</figcaption>\n</figure>\n<p>你可以将一个普通的 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">unittest.TestCase</code></a> 转换为任何一个子类：将你的测试基类从 <code class=\"docutils literal notranslate\">unittest.TestCase</code> 改为子类。所有标准的 Python 单元测试功能都将是可用的，并且它将被一些有用的附加功能所增强，如下面每节所述。</p>\n<section id=\"simpletestcase\">\n<h3><code class=\"docutils literal notranslate\">SimpleTestCase</code><a class=\"heading-anchor\" href=\"#simpletestcase\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">SimpleTestCase</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase\"><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 external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">unittest.TestCase</code></a> 的一个子类，增加了以下功能：</p>\n<ul class=\"simple\">\n<li><p>一些有用的断言，例如：</p>\n<ul>\n<li><p>检查一个可调用对象 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertRaisesMessage\" title=\"django.test.SimpleTestCase.assertRaisesMessage\"><code class=\"xref py py-meth docutils literal notranslate\">会引发某个异常</code></a>。</p></li>\n<li><p>检查一个可调用对象 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertWarnsMessage\" title=\"django.test.SimpleTestCase.assertWarnsMessage\"><code class=\"xref py py-meth docutils literal notranslate\">会触发某个警告</code></a>。</p></li>\n<li><p>测试表单字段 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertFieldOutput\" title=\"django.test.SimpleTestCase.assertFieldOutput\"><code class=\"xref py py-meth docutils literal notranslate\">渲染和错误处理</code></a>。</p></li>\n<li><p>测试 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertContains\" title=\"django.test.SimpleTestCase.assertContains\"><code class=\"xref py py-meth docutils literal notranslate\">HTML 响应是否存在／缺乏给定的片段</code></a>。</p></li>\n<li><p>验证模板 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertTemplateUsed\" title=\"django.test.SimpleTestCase.assertTemplateUsed\"><code class=\"xref py py-meth docutils literal notranslate\">是否被用于生成给定的响应内容</code></a>。</p></li>\n<li><p>验证两个 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertURLEqual\" title=\"django.test.SimpleTestCase.assertURLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">URL</code></a> 是否相等。</p></li>\n<li><p>Verifying an HTTP <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertRedirects\" title=\"django.test.SimpleTestCase.assertRedirects\"><code class=\"xref py py-meth docutils literal notranslate\">redirect</code></a> is\nperformed by the app.</p></li>\n<li><p>严格测试两个 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\" title=\"django.test.SimpleTestCase.assertHTMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">HTML 片段</code></a> 是否相等或 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertInHTML\" title=\"django.test.SimpleTestCase.assertInHTML\"><code class=\"xref py py-meth docutils literal notranslate\">包含</code></a>。</p></li>\n<li><p>严格测试两个 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertXMLEqual\" title=\"django.test.SimpleTestCase.assertXMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">XML 片段</code></a> 是否相等。</p></li>\n<li><p>严格测试两个 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertJSONEqual\" title=\"django.test.SimpleTestCase.assertJSONEqual\"><code class=\"xref py py-meth docutils literal notranslate\">JSON 片段</code></a> 相等。</p></li>\n</ul>\n</li>\n<li><p>能够用 <a class=\"reference internal\" href=\"#overriding-settings\"><span class=\"std std-ref\">修改后的配置</span></a> 运行测试。</p></li>\n<li><p>使用 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.client\" title=\"django.test.SimpleTestCase.client\"><code class=\"xref py py-attr docutils literal notranslate\">client</code></a> <a class=\"reference internal\" href=\"#django.test.Client\" title=\"django.test.Client\"><code class=\"xref py py-class docutils literal notranslate\">Client</code></a>。</p></li>\n</ul>\n<p>如果你的测试进行任何数据库查询，请使用子类 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase\" title=\"django.test.TransactionTestCase\"><code class=\"xref py py-class docutils literal notranslate\">TransactionTestCase</code></a> 或 <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">TestCase</code></a>。</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.databases\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">databases</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.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.SimpleTestCase\" title=\"django.test.SimpleTestCase\"><code class=\"xref py py-class docutils literal notranslate\">SimpleTestCase</code></a> 默认不允许数据库查询。这有助于避免执行写查询而影响其他测试，因为每个 <code class=\"docutils literal notranslate\">SimpleTestCase</code> 测试不是在事务中运行的。如果你不关心这个问题，你可以通过在你的测试类上设置 <code class=\"docutils literal notranslate\">databases</code> 类属性为 <code class=\"docutils literal notranslate\">'__all__'</code> 来禁止这个行为。</p>\n</dd></dl>\n\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p><code class=\"docutils literal notranslate\">SimpleTestCase</code> 和它的子类（如 <code class=\"docutils literal notranslate\">TestCase</code>）依靠 <code class=\"docutils literal notranslate\">setUpClass()</code> 和 <code class=\"docutils literal notranslate\">tearDownClass()</code> 来执行一些全类范围的初始化（如覆盖配置）。如果你需要覆盖这些方法，别忘了调用 <code class=\"docutils literal notranslate\">super</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\">MyTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">setUpClass</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>setUpClass<span class=\"p\">()</span>\n        <span class=\"o\">...</span>\n\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">tearDownClass</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"o\">...</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>tearDownClass<span class=\"p\">()</span>\n</code></pre></div>\n<p>如果在 <code class=\"docutils literal notranslate\">setUpClass()</code> 过程中出现异常，一定要考虑到 Python 的行为。如果发生这种情况，类中的测试和 <code class=\"docutils literal notranslate\">tearDownClass()</code> 都不会被运行。在 <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">django.test.TestCase</code></a> 的情况下，这将会泄露在 <code class=\"docutils literal notranslate\">super()</code> 中创建的事务，从而导致各种症状，包括在某些平台上的分段故障（在 macOS 上报告）。如果你想在 <code class=\"docutils literal notranslate\">setUpClass()</code> 中故意引发一个异常，如 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.SkipTest\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\">unittest.SkipTest</code></a>，一定要在调用 <code class=\"docutils literal notranslate\">super()</code> 之前进行，以避免这种情况。</p>\n</aside>\n</section>\n<section id=\"transactiontestcase\">\n<h3><code class=\"docutils literal notranslate\">TransactionTestCase</code><a class=\"heading-anchor\" href=\"#transactiontestcase\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">TransactionTestCase</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\">TransactionTestCase</code> 继承自 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase\" title=\"django.test.SimpleTestCase\"><code class=\"xref py py-class docutils literal notranslate\">SimpleTestCase</code></a> 以增加一些数据库特有的功能：</p>\n<ul class=\"simple\">\n<li><p>在每次测试开始时将数据库重新设置为已知状态，以方便测试和使用 ORM。</p></li>\n<li><p>数据库 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase.fixtures\" title=\"django.test.TransactionTestCase.fixtures\"><code class=\"xref py py-attr docutils literal notranslate\">fixtures</code></a>.</p></li>\n<li><p>测试 <a class=\"reference internal\" href=\"#skipping-tests\"><span class=\"std std-ref\">基于数据库后端功能的跳过</span></a>.</p></li>\n<li><p>其他专门的 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase.assertQuerysetEqual\" title=\"django.test.TransactionTestCase.assertQuerysetEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assert*</code></a> 方法。</p></li>\n</ul>\n<p>Django 的 <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">TestCase</code></a> 类是 <code class=\"docutils literal notranslate\">TransactionTestCase</code> 的一个比较常用的子类，它利用数据库事务设施来加快在每次测试开始时将数据库重置到已知状态的过程。然而，这样做的一个后果是，有些数据库行为不能在 Django <code class=\"docutils literal notranslate\">TestCase</code> 类中进行测试。例如，你不能像使用 <code class=\"xref py py-meth docutils literal notranslate\">select_for_update()</code> 时那样，测试一个代码块是否在一个事务中执行。在这些情况下，你应该使用 <code class=\"docutils literal notranslate\">TransactionTestCase</code>。</p>\n<p><code class=\"docutils literal notranslate\">TransactionTestCase</code> 和 <code class=\"docutils literal notranslate\">TestCase</code> 除了将数据库重设为已知状态的方式和测试与测试提交和回滚效果的相关代码外，其他都是相同的。</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">TransactionTestCase</code> 在测试运行后，通过清空所有表来重置数据库。<code class=\"docutils literal notranslate\">TransactionTestCase</code> 可以调用提交和回滚，并观察这些调用对数据库的影响。</p></li>\n<li><p>另一方面，<code class=\"docutils literal notranslate\">TestCase</code> 在测试后不清空表。相反，它将测试代码包含在数据库事务中，在测试结束后回滚。这保证了测试结束时的回滚能将数据库恢复到初始状态。</p></li>\n</ul>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>在不支持回滚的数据库上运行的 <code class=\"docutils literal notranslate\">TestCase</code> （例如 MyISAM 存储引擎的 MySQL ），则 <code class=\"docutils literal notranslate\">TransactionTestCase</code> 的所有实例，将在测试结束时回滚，删除测试数据库中的所有数据。</p>\n<p>应用 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/testing/overview/#test-case-serialized-rollback\"><span class=\"std std-ref\">不会看到他们的数据被重新加载</span></a>；如果你需要这个功能（例如，第三方应用应该启用这个功能），你可以在 <code class=\"docutils literal notranslate\">TestCase</code> 中设置 <code class=\"docutils literal notranslate\">serialized_rollback = True</code>。</p>\n</aside>\n</section>\n<section id=\"testcase\">\n<h3><code class=\"docutils literal notranslate\">TestCase</code><a class=\"heading-anchor\" href=\"#testcase\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.TestCase\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">TestCase</span><a class=\"heading-anchor\" href=\"#django.test.TestCase\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>这是 Django 中最常用的编写测试的类。它继承自 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase\" title=\"django.test.TransactionTestCase\"><code class=\"xref py py-class docutils literal notranslate\">TransactionTestCase</code></a> （以及扩展自 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase\" title=\"django.test.SimpleTestCase\"><code class=\"xref py py-class docutils literal notranslate\">SimpleTestCase</code></a>）。如果你的 Django 应用程序不使用数据库，就使用 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase\" title=\"django.test.SimpleTestCase\"><code class=\"xref py py-class docutils literal notranslate\">SimpleTestCase</code></a>。</p>\n<p>此类：</p>\n<ul class=\"simple\">\n<li><p>在两个嵌套的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/db/transactions/#django.db.transaction.atomic\" title=\"django.db.transaction.atomic\"><code class=\"xref py py-func docutils literal notranslate\">atomic()</code></a> 块中封装测试：一个用于整个类，一个用于每个测试。因此，如果你想测试一些特定的数据库事务行为，可以使用 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase\" title=\"django.test.TransactionTestCase\"><code class=\"xref py py-class docutils literal notranslate\">TransactionTestCase</code></a>。</p></li>\n<li><p>在每次测试结束时检查可延迟的数据库约束。</p></li>\n</ul>\n<p>它还提供了另一种方法：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.TestCase.setUpTestData\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-prename descclassname\">TestCase.</span><span class=\"sig-name descname\">setUpTestData</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.TestCase.setUpTestData\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>上文所述的类级 <code class=\"docutils literal notranslate\">atomic</code> 块允许在类级创建初始数据，整个 <code class=\"docutils literal notranslate\">TestCase</code> 只需一次。与使用 <code class=\"docutils literal notranslate\">setUp()</code> 相比，这种技术允许更快的测试。</p>\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.test</span> <span class=\"kn\">import</span> TestCase\n\n<span class=\"k\">class</span> <span class=\"nc\">MyTests</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">setUpTestData</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Set up data for the whole TestCase</span>\n        <span class=\"bp\">cls</span><span class=\"o\">.</span>foo <span class=\"o\">=</span> Foo<span class=\"o\">.</span>objects<span class=\"o\">.</span>create<span class=\"p\">(</span>bar<span class=\"o\">=</span><span class=\"s2\">&quot;Test&quot;</span><span class=\"p\">)</span>\n        <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test1</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Some test using self.foo</span>\n        <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Some other test using self.foo</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p>请注意，如果测试是在没有事务支持的数据库上运行（例如，MyISAM 引擎的 MySQL），<code class=\"docutils literal notranslate\">setUpTestData()</code> 将在每次测试前被调用，从而降低了速度优势。</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\">setUpTestData()</code> 中分配给类属性的对象必须支持用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/copy.html#copy.deepcopy\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">copy.deepcopy()</code></a> 来创建深度拷贝，以便将它们与每个测试方法所做的改变隔离。在以前的 Django 版本中，这些对象被重复使用，对它们所做的改变在测试方法之间持续存在。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.TestCase.captureOnCommitCallbacks\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-prename descclassname\">TestCase.</span><span class=\"sig-name descname\">captureOnCommitCallbacks</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">using<span class=\"o\">=</span><span class=\"default_value\">DEFAULT_DB_ALIAS</span></em>, <em class=\"sig-param\">execute<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.TestCase.captureOnCommitCallbacks\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"version-note version-added\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">New in Django 3.2</p></aside>\n<p>返回一个为给定的数据库连接捕获 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/db/transactions/#django.db.transaction.on_commit\" title=\"django.db.transaction.on_commit\"><code class=\"xref py py-func docutils literal notranslate\">transaction.on_commit()</code></a> 回调的上下文管理器。它返回一个列表，其中包含在退出上下文时，捕获的回调函数。从这个列表中，你可以对回调进行断言，或者调用它们来获得其副作用，模拟一个提交。</p>\n<p><code class=\"docutils literal notranslate\">using</code> 是数据库连接的别名，用于捕获回调。</p>\n<p>如果 <code class=\"docutils literal notranslate\">execute</code> 是 <code class=\"docutils literal notranslate\">True</code>，并且如果没有发生异常，所有的回调将在上下文管理器退出时被调用。这模拟了在包裹的代码块之后的提交。</p>\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.core</span> <span class=\"kn\">import</span> mail\n<span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> TestCase\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ContactTests</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_post</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>captureOnCommitCallbacks<span class=\"p\">(</span>execute<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span> <span class=\"k\">as</span> callbacks<span class=\"p\">:</span>\n            response <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>client<span class=\"o\">.</span>post<span class=\"p\">(</span>\n                <span class=\"s1\">&#39;/contact/&#39;</span><span class=\"p\">,</span>\n                <span class=\"p\">{</span><span class=\"s1\">&#39;message&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;I like your site&#39;</span><span class=\"p\">},</span>\n            <span class=\"p\">)</span>\n\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        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span>callbacks<span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span>mail<span class=\"o\">.</span>outbox<span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>mail<span class=\"o\">.</span>outbox<span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span>subject<span class=\"p\">,</span> <span class=\"s1\">&#39;Contact Form&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>mail<span class=\"o\">.</span>outbox<span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span>body<span class=\"p\">,</span> <span class=\"s1\">&#39;I like your site&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<aside class=\"version-note version-changed\" data-version=\"4.0\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 4.0</p><p>In older versions, new callbacks added while executing\n<a class=\"reference internal\" href=\"/zh-hans/4.0/topics/db/transactions/#django.db.transaction.on_commit\" title=\"django.db.transaction.on_commit\"><code class=\"xref py py-func docutils literal notranslate\">transaction.on_commit()</code></a> callbacks were not captured.</p>\n</aside>\n</dd></dl>\n\n</section>\n<section id=\"liveservertestcase\">\n<span id=\"live-test-server\"></span><h3><code class=\"docutils literal notranslate\">LiveServerTestCase</code><a class=\"heading-anchor\" href=\"#liveservertestcase\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.test.LiveServerTestCase\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-name descname\">LiveServerTestCase</span><a class=\"heading-anchor\" href=\"#django.test.LiveServerTestCase\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\">LiveServerTestCase</code> 和 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase\" title=\"django.test.TransactionTestCase\"><code class=\"xref py py-class docutils literal notranslate\">TransactionTestCase</code></a> 的功能基本相同，但多了一个功能：它在设置时在后台启动一个实时的 Django 服务器，并在关闭时将其关闭。这就允许使用 <a class=\"reference internal\" href=\"#test-client\"><span class=\"std std-ref\">Django 虚拟客户端</span></a> 以外的自动化测试客户端，例如，<a class=\"reference external\" href=\"https://www.selenium.dev/\">Selenium</a> 客户端，在浏览器内执行一系列功能测试，并模拟真实用户的操作。</p>\n<p>实时服务器在 <code class=\"docutils literal notranslate\">localhost</code> 上监听，并绑定到 0 号端口，0 号端口使用操作系统分配的一个空闲端口。在测试过程中可以用 <code class=\"docutils literal notranslate\">self.live_server_url</code> 访问服务器的 URL。</p>\n<p>为了演示如何使用 <code class=\"docutils literal notranslate\">LiveServerTestCase</code>，让我们写一个 Selenium 测试。首先，你需要将 <a class=\"reference external\" href=\"https://pypi.org/project/selenium/\">selenium package</a> 安装到你的 Python 路径中。</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-0-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code><span class=\"gp\">$ </span>python -m pip install selenium\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-0-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</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=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py -m pip install selenium\n</code></pre></div></div></div>\n<p>然后，在你的应用程序的测试模块中添加一个基于 <code class=\"docutils literal notranslate\">LiveServerTestCase</code> 的测试（例如：<code class=\"docutils literal notranslate\">myapp/tests.py</code>）。在这个例子中，我们将假设你正在使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/staticfiles/#module-django.contrib.staticfiles\" title=\"django.contrib.staticfiles: An app for handling static files.\"><code class=\"xref py py-mod docutils literal notranslate\">staticfiles</code></a> 应用，并且希望在执行测试时提供类似于我们在开发时使用 <code class=\"docutils literal notranslate\">DEBUG=True</code> 得到的静态文件，即不必使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/staticfiles/#django-admin-collectstatic\"><code class=\"xref std std-djadmin docutils literal notranslate\">collectstatic</code></a> 收集它们。我们将使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/contrib/staticfiles/#django.contrib.staticfiles.testing.StaticLiveServerTestCase\" title=\"django.contrib.staticfiles.testing.StaticLiveServerTestCase\"><code class=\"xref py py-class docutils literal notranslate\">StaticLiveServerTestCase</code></a> 子类，它提供了这个功能。如果不需要的话，可以用 <code class=\"docutils literal notranslate\">django.test.LiveServerTestCase</code> 代替。</p>\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.staticfiles.testing</span> <span class=\"kn\">import</span> StaticLiveServerTestCase\n<span class=\"kn\">from</span> <span class=\"nn\">selenium.webdriver.firefox.webdriver</span> <span class=\"kn\">import</span> WebDriver\n\n<span class=\"k\">class</span> <span class=\"nc\">MySeleniumTests</span><span class=\"p\">(</span>StaticLiveServerTestCase<span class=\"p\">):</span>\n    fixtures <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;user-data.json&#39;</span><span class=\"p\">]</span>\n\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">setUpClass</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>setUpClass<span class=\"p\">()</span>\n        <span class=\"bp\">cls</span><span class=\"o\">.</span>selenium <span class=\"o\">=</span> WebDriver<span class=\"p\">()</span>\n        <span class=\"bp\">cls</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>implicitly_wait<span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n\n    <span class=\"nd\">@classmethod</span>\n    <span class=\"k\">def</span> <span class=\"nf\">tearDownClass</span><span class=\"p\">(</span><span class=\"bp\">cls</span><span class=\"p\">):</span>\n        <span class=\"bp\">cls</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>quit<span class=\"p\">()</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>tearDownClass<span class=\"p\">()</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_login</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">%s%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>live_server_url<span class=\"p\">,</span> <span class=\"s1\">&#39;/login/&#39;</span><span class=\"p\">))</span>\n        username_input <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>find_element_by_name<span class=\"p\">(</span><span class=\"s2\">&quot;username&quot;</span><span class=\"p\">)</span>\n        username_input<span class=\"o\">.</span>send_keys<span class=\"p\">(</span><span class=\"s1\">&#39;myuser&#39;</span><span class=\"p\">)</span>\n        password_input <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>find_element_by_name<span class=\"p\">(</span><span class=\"s2\">&quot;password&quot;</span><span class=\"p\">)</span>\n        password_input<span class=\"o\">.</span>send_keys<span class=\"p\">(</span><span class=\"s1\">&#39;secret&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>find_element_by_xpath<span class=\"p\">(</span><span class=\"s1\">&#39;//input[@value=&quot;Log in&quot;]&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span>click<span class=\"p\">()</span>\n</code></pre></div>\n<p>最后，你可以按以下方式进行测试：</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-1-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code><span class=\"gp\">$ </span>./manage.py <span class=\"nb\">test</span> myapp.tests.MySeleniumTests.test_login\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-1-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</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=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> manage.py test myapp.tests.MySeleniumTests.test_login\n</code></pre></div></div></div>\n<p>这个例子会自动打开 Firefox，然后进入登录页面，输入凭证并按“登录”按钮。Selenium 提供了其他驱动程序，以防你没有安装 Firefox 或希望使用其他浏览器。上面的例子只是 Selenium 客户端能做的一小部分，更多细节请查看 <a class=\"reference external\" href=\"https://selenium-python.readthedocs.io/api.html\">full reference</a>。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>当使用内存 SQLite 数据库运行测试时，同一个数据库连接将由两个线程并行共享：运行实时服务器的线程和运行测试用例的线程。要防止两个线程通过这个共享连接同时进行数据库查询，因为这有时可能会随机导致测试失败。所以你需要确保两个线程不会同时访问数据库。特别是，这意味着在某些情况下（例如，刚刚点击一个链接或提交一个表单之后），你可能需要检查 Selenium 是否收到了响应，并且在继续执行进一步的测试之前，检查下一个页面是否被加载。例如，让 Selenium 等待直到在响应中找到 <code class=\"docutils literal notranslate\">&lt;body&gt;</code> HTML 标签（需要 Selenium &gt; 2.13）：</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\">def</span> <span class=\"nf\">test_login</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"kn\">from</span> <span class=\"nn\">selenium.webdriver.support.wait</span> <span class=\"kn\">import</span> WebDriverWait\n    timeout <span class=\"o\">=</span> <span class=\"mi\">2</span>\n    <span class=\"o\">...</span>\n    <span class=\"bp\">self</span><span class=\"o\">.</span>selenium<span class=\"o\">.</span>find_element_by_xpath<span class=\"p\">(</span><span class=\"s1\">&#39;//input[@value=&quot;Log in&quot;]&#39;</span><span class=\"p\">)</span><span class=\"o\">.</span>click<span class=\"p\">()</span>\n    <span class=\"c1\"># Wait until the response is received</span>\n    WebDriverWait<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>selenium<span class=\"p\">,</span> timeout<span class=\"p\">)</span><span class=\"o\">.</span>until<span class=\"p\">(</span>\n        <span class=\"k\">lambda</span> driver<span class=\"p\">:</span> driver<span class=\"o\">.</span>find_element_by_tag_name<span class=\"p\">(</span><span class=\"s1\">&#39;body&#39;</span><span class=\"p\">))</span>\n</code></pre></div>\n<p>The tricky thing here is that there's really no such thing as a &quot;page load,&quot;\nespecially in modern web apps that generate HTML dynamically after the\nserver generates the initial document. So, checking for the presence of\n<code class=\"docutils literal notranslate\">&lt;body&gt;</code> in the response might not necessarily be appropriate for all use\ncases. Please refer to the <a class=\"reference external\" href=\"https://web.archive.org/web/20160129132110/http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_WebDriver_fails_to_find_elements_/_Does_not_block_on_page_loa\">Selenium FAQ</a> and <a class=\"reference external\" href=\"https://www.selenium.dev/documentation/webdriver/waits/#explicit-wait\">Selenium documentation</a>\nfor more information.</p>\n</aside>\n</section>\n</section>\n<section id=\"test-cases-features\">\n<h2>测试用例特性<a class=\"heading-anchor\" href=\"#test-cases-features\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"default-test-client\">\n<h3>默认测试客户端<a class=\"heading-anchor\" href=\"#default-test-client\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.client\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">client</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.client\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\">django.test.*TestCase</code> 实例中的每个测试用例都可以访问一个 Django 测试客户端的实例。这个客户端可以用 <code class=\"docutils literal notranslate\">self.client</code> 来访问。这个客户端在每个测试中都会被重新创建，所以你不必担心状态（比如 cookie）会从一个测试转移到另一个测试中。</p>\n<p>这意味着，不必每个测试中实例化一个 <code class=\"docutils literal notranslate\">Client</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\">unittest</span>\n<span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> Client\n\n<span class=\"k\">class</span> <span class=\"nc\">SimpleTest</span><span class=\"p\">(</span>unittest<span class=\"o\">.</span>TestCase<span class=\"p\">):</span>\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        client <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n        response <span class=\"o\">=</span> client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customer/details/&#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\n    <span class=\"k\">def</span> <span class=\"nf\">test_index</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        client <span class=\"o\">=</span> Client<span class=\"p\">()</span>\n        response <span class=\"o\">=</span> client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/customer/index/&#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>......你可以引用 <code class=\"docutils literal notranslate\">self.client</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\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\">test_details</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;/customer/details/&#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\n    <span class=\"k\">def</span> <span class=\"nf\">test_index</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;/customer/index/&#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</section>\n<section id=\"customizing-the-test-client\">\n<h3>自定义测试客户端<a class=\"heading-anchor\" href=\"#customizing-the-test-client\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.client_class\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">client_class</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.client_class\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果你想使用不同的 <code class=\"docutils literal notranslate\">Client</code> 类（例如，一个具有自定义行为的子类），使用 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.client_class\" title=\"django.test.SimpleTestCase.client_class\"><code class=\"xref py py-attr docutils literal notranslate\">client_class</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><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> Client<span class=\"p\">,</span> TestCase\n\n<span class=\"k\">class</span> <span class=\"nc\">MyTestClient</span><span class=\"p\">(</span>Client<span class=\"p\">):</span>\n    <span class=\"c1\"># Specialized methods for your environment</span>\n    <span class=\"o\">...</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MyTest</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    client_class <span class=\"o\">=</span> MyTestClient\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_my_stuff</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Here self.client is an instance of MyTestClient...</span>\n        call_some_test_code<span class=\"p\">()</span>\n</code></pre></div>\n</section>\n<section id=\"fixture-loading\">\n<span id=\"topics-testing-fixtures\"></span><h3>辅助工具加载<a class=\"heading-anchor\" href=\"#fixture-loading\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase.fixtures\">\n<span class=\"sig-prename descclassname\">TransactionTestCase.</span><span class=\"sig-name descname\">fixtures</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase.fixtures\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果数据库中没有任何数据，那么数据库支持的网站的测试用例就没什么用了。测试使用ORM创建对象更易读，也更易维护，例如在 <a class=\"reference internal\" href=\"#django.test.TestCase.setUpTestData\" title=\"django.test.TestCase.setUpTestData\"><code class=\"xref py py-meth docutils literal notranslate\">TestCase.setUpTestData()</code></a> 中。但是，你也可以使用辅助工具。</p>\n<p>辅助工具是 Django 知道如何导入数据库的数据集合。例如，如果你的网站有用户账户，你可能会设置一个假用户账户的辅助工具，以便在测试时填充你的数据库。</p>\n<p>创建辅助工具的最直接方法是使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/django-admin/#django-admin-dumpdata\"><code class=\"xref std std-djadmin docutils literal notranslate\">manage.py dumpdata</code></a> 命令。这假定你已经在你的数据库中拥有一些数据。参见 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/django-admin/#django-admin-dumpdata\"><code class=\"xref std std-djadmin docutils literal notranslate\">dumpdata 文档</code></a> 了解更多细节。</p>\n<p>一旦你创建了一个辅助工具，并把它放在你的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 中的 <code class=\"docutils literal notranslate\">fixtures</code> 目录下，你就可以通过在你的 <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">django.test.TestCase</code></a> 子类上指定一个 <code class=\"docutils literal notranslate\">fixtures</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\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Animal\n\n<span class=\"k\">class</span> <span class=\"nc\">AnimalTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    fixtures <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;mammals.json&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;birds&#39;</span><span class=\"p\">]</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=\"c1\"># Test definitions as before.</span>\n        call_setup_methods<span class=\"p\">()</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_fluffy_animals</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># A test that uses the fixtures.</span>\n        call_some_test_code<span class=\"p\">()</span>\n</code></pre></div>\n<p>具体来说，将发生以下情况：</p>\n<ul class=\"simple\">\n<li><p>在每次测试开始时，在 <code class=\"docutils literal notranslate\">setUp()</code> 运行之前，Django 会对数据库进行刷新，将数据库直接返回到 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">migrate</code></a> 被调用后的状态。</p></li>\n<li><p>然后，所有命名的辅助工具都会被安装。在这个例子中，Django 将安装任何名为 <code class=\"docutils literal notranslate\">mammals</code> 的 JSON 辅助工具，然后是任何名为 <code class=\"docutils literal notranslate\">birds</code> 的辅助工具。请参阅 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/django-admin/#django-admin-loaddata\"><code class=\"xref std std-djadmin docutils literal notranslate\">loaddata</code></a> 文档，了解更多关于定义和安装辅助工具的细节。</p></li>\n</ul>\n<p>出于性能方面的考虑， <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">TestCase</code></a> 在 <a class=\"reference internal\" href=\"#django.test.TestCase.setUpTestData\" title=\"django.test.TestCase.setUpTestData\"><code class=\"xref py py-meth docutils literal notranslate\">setUpTestData()</code></a> 之前为整个测试类加载一次辅助工具，而不是在每次测试之前加载，并且它在每次测试之前使用事务来清理数据库。在任何情况下，你都可以确定一个测试的结果不会受到另一个测试或测试执行顺序的影响。</p>\n<p>默认情况下，辅助工具只被加载到 <code class=\"docutils literal notranslate\">default</code> 数据库中。如果你使用多个数据库并且设置了 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase.databases\" title=\"django.test.TransactionTestCase.databases\"><code class=\"xref py py-attr docutils literal notranslate\">TransactionTestCase.databases</code></a>，辅助工具将被加载到所有指定的数据库中。</p>\n</section>\n<section id=\"urlconf-configuration\">\n<h3>URLconf 配置<a class=\"heading-anchor\" href=\"#urlconf-configuration\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你的应用程序提供了视图，你可能希望包含使用测试客户端来行使这些视图的测试。然而，最终用户可以自由地在他们选择的任何 URL 上部署应用程序中的视图。这意味着你的测试不能依赖于你的视图将在特定的 URL 上可用这一事实。用 <code class=\"docutils literal notranslate\">&#64;override_settings(ROOT_URLCONF=...)</code> 来装饰你的测试类或测试方法的 URLconf 配置。</p>\n</section>\n<section id=\"multi-database-support\">\n<span id=\"testing-multi-db\"></span><h3>多数据库支持<a class=\"heading-anchor\" href=\"#multi-database-support\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase.databases\">\n<span class=\"sig-prename descclassname\">TransactionTestCase.</span><span class=\"sig-name descname\">databases</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase.databases\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>Django 设置了一个测试数据库，对应于你设置中的 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 定义的并且至少有一个测试引用了 <code class=\"docutils literal notranslate\">databases</code> 的每个数据库。</p>\n<p>然而，运行一个 Django <code class=\"docutils literal notranslate\">TestCase</code> 所花费的时间很大一部分是被调用 <code class=\"docutils literal notranslate\">flush</code> 所消耗的，它确保了你在每次测试运行开始时有一个干净的数据库。如果你有多个数据库，就需要多次刷新（每个数据库一个），这可能是一个耗时的活动——特别是当你的测试不需要测试多数据库活动时。</p>\n<p>作为一种优化，Django 只在每次测试运行开始时刷新 <code class=\"docutils literal notranslate\">default</code> 数据库。如果你的设置包含多个数据库，并且你的测试要求每个数据库都是干净的，你可以使用测试套件上的 <code class=\"docutils literal notranslate\">databases</code> 属性来请求额外的数据库被刷新。</p>\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=\"k\">class</span> <span class=\"nc\">TestMyViews</span><span class=\"p\">(</span>TransactionTestCase<span class=\"p\">):</span>\n    databases <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;default&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;other&#39;</span><span class=\"p\">}</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_index_page_view</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        call_some_test_code<span class=\"p\">()</span>\n</code></pre></div>\n<p>这个测试用例将在运行 <code class=\"docutils literal notranslate\">test_index_page_view</code> 之前刷新 <code class=\"docutils literal notranslate\">default</code> 和 <code class=\"docutils literal notranslate\">other</code> 测试数据库。你也可以使用 <code class=\"docutils literal notranslate\">'__all__'</code> 来指定所有的测试数据库必须被刷新。</p>\n<p><code class=\"docutils literal notranslate\">databases</code> 标志也控制 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase.fixtures\" title=\"django.test.TransactionTestCase.fixtures\"><code class=\"xref py py-attr docutils literal notranslate\">TransactionTestCase.fixtures</code></a> 被加载到哪些数据库。默认情况下，辅助工具只被加载到 <code class=\"docutils literal notranslate\">default</code> 数据库中。</p>\n<p>对不在 <code class=\"docutils literal notranslate\">databases</code> 中的数据库的查询将给出断言错误，以防止测试之间的状态泄露。</p>\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.test.TestCase.databases\">\n<span class=\"sig-prename descclassname\">TestCase.</span><span class=\"sig-name descname\">databases</span><a class=\"heading-anchor\" href=\"#django.test.TestCase.databases\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>默认情况下，在 <code class=\"docutils literal notranslate\">TestCase</code> 期间，仅将 <code class=\"docutils literal notranslate\">default</code> 数据库包装在事务中，并且尝试查询其他数据库将导致断言错误，以防止测试之间的状态泄漏。</p>\n<p>在测试类上使用 <code class=\"docutils literal notranslate\">databases</code> 类属性来请求对非 <code class=\"docutils literal notranslate\">default</code> 数据库进行事务包装。</p>\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=\"k\">class</span> <span class=\"nc\">OtherDBTests</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    databases <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;other&#39;</span><span class=\"p\">}</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_other_db_query</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p>这个测试只允许对 <code class=\"docutils literal notranslate\">other</code> 数据库进行查询。就像 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.databases\" title=\"django.test.SimpleTestCase.databases\"><code class=\"xref py py-attr docutils literal notranslate\">SimpleTestCase.databases</code></a> 和 <a class=\"reference internal\" href=\"#django.test.TransactionTestCase.databases\" title=\"django.test.TransactionTestCase.databases\"><code class=\"xref py py-attr docutils literal notranslate\">TransactionTestCase.databases</code></a> 一样，<code class=\"docutils literal notranslate\">'__all__'</code> 常量可以用来指定测试应该允许对所有数据库进行查询。</p>\n</section>\n<section id=\"overriding-settings\">\n<span id=\"id1\"></span><h3>覆盖配置<a class=\"heading-anchor\" href=\"#overriding-settings\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>使用下面的函数可以临时改变测试中的设置值。不要直接操作 <code class=\"docutils literal notranslate\">django.conf.settings</code>，因为 Django 不会在这种操作后恢复原始值。</p>\n</aside>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.settings\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">settings</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.settings\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>为了测试的目的，经常需要临时改变一个设置，并在运行测试代码后恢复到原始值。对于这个用例，Django 提供了一个标准的 Python 上下文管理器（见 <span class=\"target\" id=\"index-7\"></span><a class=\"pep reference external\" href=\"https://peps.python.org/pep-0343/\"><strong>PEP 343</strong></a>），叫做 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.settings\" title=\"django.test.SimpleTestCase.settings\"><code class=\"xref py py-meth docutils literal notranslate\">settings()</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><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\">LoginTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_login</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n\n        <span class=\"c1\"># First check for the default behavior</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;/sekrit/&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertRedirects<span class=\"p\">(</span>response<span class=\"p\">,</span> <span class=\"s1\">&#39;/accounts/login/?next=/sekrit/&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Then override the LOGIN_URL setting</span>\n        <span class=\"k\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>settings<span class=\"p\">(</span>LOGIN_URL<span class=\"o\">=</span><span class=\"s1\">&#39;/other/login/&#39;</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;/sekrit/&#39;</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span>assertRedirects<span class=\"p\">(</span>response<span class=\"p\">,</span> <span class=\"s1\">&#39;/other/login/?next=/sekrit/&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>This example will override the <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-LOGIN_URL\"><code class=\"xref std std-setting docutils literal notranslate\">LOGIN_URL</code></a> setting for the code\nin the <code class=\"docutils literal notranslate\">with</code> block and reset its value to the previous state afterward.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.modify_settings\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">modify_settings</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.modify_settings\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>重新定义包含一系列值的设置可能会很麻烦。在实践中，添加或删除值通常是足够的。Django 提供了 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.modify_settings\" title=\"django.test.SimpleTestCase.modify_settings\"><code class=\"xref py py-meth docutils literal notranslate\">modify_settings()</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><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\">MiddlewareTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_cache_middleware</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>modify_settings<span class=\"p\">(</span>MIDDLEWARE<span class=\"o\">=</span><span class=\"p\">{</span>\n            <span class=\"s1\">&#39;append&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.middleware.cache.FetchFromCacheMiddleware&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;prepend&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.middleware.cache.UpdateCacheMiddleware&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;remove&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n                <span class=\"s1\">&#39;django.contrib.sessions.middleware.SessionMiddleware&#39;</span><span class=\"p\">,</span>\n                <span class=\"s1\">&#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;</span><span class=\"p\">,</span>\n                <span class=\"s1\">&#39;django.contrib.messages.middleware.MessageMiddleware&#39;</span><span class=\"p\">,</span>\n            <span class=\"p\">],</span>\n        <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;/&#39;</span><span class=\"p\">)</span>\n            <span class=\"c1\"># ...</span>\n</code></pre></div>\n<p>对于每个操作，你可以提供一个值的列表或一个字符串。当值已经存在于列表中时，<code class=\"docutils literal notranslate\">append</code> 和 <code class=\"docutils literal notranslate\">prepend</code> 没有效果；当值不存在时，<code class=\"docutils literal notranslate\">remove</code> 也没有效果。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.override_settings\">\n<span class=\"sig-name descname\">override_settings</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.override_settings\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果你想覆盖一个测试方法的设置，Django 提供了 <a class=\"reference internal\" href=\"#django.test.override_settings\" title=\"django.test.override_settings\"><code class=\"xref py py-func docutils literal notranslate\">override_settings()</code></a> 装饰器（见 <span class=\"target\" id=\"index-8\"></span><a class=\"pep reference external\" href=\"https://peps.python.org/pep-0318/\"><strong>PEP 318</strong></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><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\">LoginTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"nd\">@override_settings</span><span class=\"p\">(</span>LOGIN_URL<span class=\"o\">=</span><span class=\"s1\">&#39;/other/login/&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_login</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;/sekrit/&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertRedirects<span class=\"p\">(</span>response<span class=\"p\">,</span> <span class=\"s1\">&#39;/other/login/?next=/sekrit/&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>装饰器也可以应用于 <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">TestCase</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><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=\"nd\">@override_settings</span><span class=\"p\">(</span>LOGIN_URL<span class=\"o\">=</span><span class=\"s1\">&#39;/other/login/&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">class</span> <span class=\"nc\">LoginTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_login</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;/sekrit/&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertRedirects<span class=\"p\">(</span>response<span class=\"p\">,</span> <span class=\"s1\">&#39;/other/login/?next=/sekrit/&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.modify_settings\">\n<span class=\"sig-name descname\">modify_settings</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">*</span>args</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.modify_settings\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>同样，Django 也提供了 <a class=\"reference internal\" href=\"#django.test.modify_settings\" title=\"django.test.modify_settings\"><code class=\"xref py py-func docutils literal notranslate\">modify_settings()</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><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> TestCase<span class=\"p\">,</span> modify_settings\n\n<span class=\"k\">class</span> <span class=\"nc\">MiddlewareTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"nd\">@modify_settings</span><span class=\"p\">(</span>MIDDLEWARE<span class=\"o\">=</span><span class=\"p\">{</span>\n        <span class=\"s1\">&#39;append&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.middleware.cache.FetchFromCacheMiddleware&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;prepend&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.middleware.cache.UpdateCacheMiddleware&#39;</span><span class=\"p\">,</span>\n    <span class=\"p\">})</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_cache_middleware</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;/&#39;</span><span class=\"p\">)</span>\n        <span class=\"c1\"># ...</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><span class=\"kn\">from</span> <span class=\"nn\">django.test</span> <span class=\"kn\">import</span> TestCase<span class=\"p\">,</span> modify_settings\n\n<span class=\"nd\">@modify_settings</span><span class=\"p\">(</span>MIDDLEWARE<span class=\"o\">=</span><span class=\"p\">{</span>\n    <span class=\"s1\">&#39;append&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.middleware.cache.FetchFromCacheMiddleware&#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;prepend&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.middleware.cache.UpdateCacheMiddleware&#39;</span><span class=\"p\">,</span>\n<span class=\"p\">})</span>\n<span class=\"k\">class</span> <span class=\"nc\">MiddlewareTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">test_cache_middleware</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;/&#39;</span><span class=\"p\">)</span>\n        <span class=\"c1\"># ...</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>当给定一个类时，这些装饰器直接修改该类并返回它，它们不会创建并返回一个修改后的副本。因此，如果你试图调整上面的例子，将返回值分配给一个不同于 <code class=\"docutils literal notranslate\">LoginTestCase</code> 或 <code class=\"docutils literal notranslate\">MiddlewareTestCase</code> 的名称，你可能会惊讶地发现，原来的测试用例类仍然同样受到装饰器的影响。对于一个给定的类，<a class=\"reference internal\" href=\"#django.test.modify_settings\" title=\"django.test.modify_settings\"><code class=\"xref py py-func docutils literal notranslate\">modify_settings()</code></a> 总是应用在 <a class=\"reference internal\" href=\"#django.test.override_settings\" title=\"django.test.override_settings\"><code class=\"xref py py-func docutils literal notranslate\">override_settings()</code></a> 之后。</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>配置文件中包含了一些设置，这些设置只有在 Django 内部初始化时才会被使用。如果你用 <code class=\"docutils literal notranslate\">override_settings</code> 改变它们，当你通过``django.conf.settings`` 模块访问会得到被改变的配置。但是，Django 的内部程序访问它的方式是不同的。实际上，使用 <a class=\"reference internal\" href=\"#django.test.override_settings\" title=\"django.test.override_settings\"><code class=\"xref py py-func docutils literal notranslate\">override_settings()</code></a> 或者 <a class=\"reference internal\" href=\"#django.test.modify_settings\" title=\"django.test.modify_settings\"><code class=\"xref py py-func docutils literal notranslate\">modify_settings()</code></a> 来使用这些设置，很可能达不到你预期的效果。</p>\n<p>我们不建议改变 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-DATABASES\"><code class=\"xref std std-setting docutils literal notranslate\">DATABASES</code></a> 的设置。改变 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 的设置是可能的，但如果你使用的是内部缓存，比如 <code class=\"xref py py-mod docutils literal notranslate\">django.contrib.session</code>，就有点棘手。例如，你必须在使用缓存会话并覆盖 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 的测试中重新初始化会话后端。</p>\n<p>最后，避免将你的配置别名为模块级常量，因为 <code class=\"docutils literal notranslate\">override_settings()</code> 不会对这些值起作用，它们只在第一次导入模块时才被评估。</p>\n</aside>\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=\"nd\">@override_settings</span><span class=\"p\">()</span>\n<span class=\"k\">def</span> <span class=\"nf\">test_something</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"k\">del</span> settings<span class=\"o\">.</span>LOGIN_URL\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>覆盖配置时，请确保处理你的应用代码使用即使保留配置更改也能保持状态的缓存或类似功能的情况。Django 提供了 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/signals/#django.test.signals.setting_changed\" title=\"django.test.signals.setting_changed\"><code class=\"xref py py-data docutils literal notranslate\">django.test.signals.setting_changed</code></a> 信号，让你在设置被改变时，可以注册回调来清理和重置状态。</p>\n<p>Django 自己也使用这个信号来重置各种数据。</p>\n<div class=\"table-scroll\" role=\"region\" tabindex=\"0\" aria-label=\"Table\"><table class=\"docutils align-default\">\n<thead>\n<tr class=\"row-odd\"><th class=\"head\"><p>覆盖配置</p></th>\n<th class=\"head\"><p>数据重置</p></th>\n</tr>\n</thead>\n<tbody>\n<tr class=\"row-even\"><td><p>USE_TZ，TIME_ZONE</p></td>\n<td><p>数据库时区</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p>TEMPLATES</p></td>\n<td><p>模板引擎</p></td>\n</tr>\n<tr class=\"row-even\"><td><p>SERIALIZATION_MODULES</p></td>\n<td><p>序列化器缓存</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p>LOCALE_PATHS，LANGUAGE_CODE</p></td>\n<td><p>默认翻译和加载的翻译</p></td>\n</tr>\n<tr class=\"row-even\"><td><p>MEDIA_ROOT，DEFAULT_FILE_STORAGE</p></td>\n<td><p>默认文件存储</p></td>\n</tr>\n</tbody>\n</table>\n</div>\n</section>\n<section id=\"emptying-the-test-outbox\">\n<span id=\"emptying-test-outbox\"></span><h3>清空测试发件箱<a class=\"heading-anchor\" href=\"#emptying-the-test-outbox\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你使用任何 Django 的自定义 <code class=\"docutils literal notranslate\">TestCase</code> 类，测试运行器将在每个测试用例开始时清除测试邮件发件箱的内容。</p>\n<p>关于测试期间电子邮件服务的更多细节，请参见下面的 <a class=\"reference internal\" href=\"#email-services\">Email services</a>。</p>\n</section>\n<section id=\"assertions\">\n<span id=\"id2\"></span><h3>断言<a class=\"heading-anchor\" href=\"#assertions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>As Python's normal <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">unittest.TestCase</code></a> class implements assertion methods\nsuch as <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">assertTrue()</code></a> and\n<a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertEqual\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">assertEqual()</code></a>, Django's custom <a class=\"reference internal\" href=\"#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\">TestCase</code></a> class\nprovides a number of custom assertion methods that are useful for testing web\napplications:</p>\n<p>大多数这些断言方法给出的失败信息可以用 <code class=\"docutils literal notranslate\">msg_prefix</code> 参数自定义。这个字符串将被加在断言产生的任何失败信息的前面。这允许你提供额外的细节，以帮助你确定测试套件中失败的位置和原因。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertRaisesMessage\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertRaisesMessage</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">expected_exception</em>, <em class=\"sig-param\">expected_message</em>, <em class=\"sig-param\">callable</em>, <em class=\"sig-param\"><span class=\"o\">*</span>args</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertRaisesMessage\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dt class=\"sig sig-object py\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertRaisesMessage</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">expected_exception</em>, <em class=\"sig-param\">expected_message</em><span class=\"sig-paren\">)</span></dt>\n<dd><p>断言执行 <code class=\"docutils literal notranslate\">callable</code> 引起 <code class=\"docutils literal notranslate\">expected_exception</code>，并且在异常信息中发现 <code class=\"docutils literal notranslate\">expected_message</code>。任何其他结果都会被报告为失败。它是 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertRaisesRegex\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">unittest.TestCase.assertRaisesRegex()</code></a> 的简单版本，不同的是 <code class=\"docutils literal notranslate\">expected_message</code> 不作为正则表达式处理。</p>\n<p>如果只给了 <code class=\"docutils literal notranslate\">expected_exception</code> 和 <code class=\"docutils literal notranslate\">expected_message</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\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>assertRaisesMessage<span class=\"p\">(</span><span class=\"ne\">ValueError</span><span class=\"p\">,</span> <span class=\"s1\">&#39;invalid literal for int()&#39;</span><span class=\"p\">):</span>\n    <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"s1\">&#39;a&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertWarnsMessage\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertWarnsMessage</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">expected_warning</em>, <em class=\"sig-param\">expected_message</em>, <em class=\"sig-param\">callable</em>, <em class=\"sig-param\"><span class=\"o\">*</span>args</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertWarnsMessage\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dt class=\"sig sig-object py\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertWarnsMessage</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">expected_warning</em>, <em class=\"sig-param\">expected_message</em><span class=\"sig-paren\">)</span></dt>\n<dd><p>类似于 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertRaisesMessage\" title=\"django.test.SimpleTestCase.assertRaisesMessage\"><code class=\"xref py py-meth docutils literal notranslate\">SimpleTestCase.assertRaisesMessage()</code></a>，但是 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertWarnsRegex\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">assertWarnsRegex()</code></a> 代替 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertRaisesRegex\" title=\"(in Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\">assertRaisesRegex()</code></a>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertFieldOutput\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertFieldOutput</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">fieldclass</em>, <em class=\"sig-param\">valid</em>, <em class=\"sig-param\">invalid</em>, <em class=\"sig-param\">field_args<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">field_kwargs<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">empty_value<span class=\"o\">=</span><span class=\"default_value\">''</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertFieldOutput\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言表单字段在不同的输入情况下表现正确。</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">参数<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><ul class=\"simple\">\n<li><p><strong>fieldclass</strong> -- 待测试字段的类。</p></li>\n<li><p><strong>valid</strong> -- 一个字典，将有效输入映射到它们的预期干净值。</p></li>\n<li><p><strong>invalid</strong> -- 一个字典，将无效输入映射到一个或多个引发的错误信息</p></li>\n<li><p><strong>field_args</strong> -- 传递给实例化字段的 args。</p></li>\n<li><p><strong>field_kwargs</strong> -- 传递给实例化字段的 kwargs。</p></li>\n<li><p><strong>empty_value</strong> -- <code class=\"docutils literal notranslate\">empty_values</code> 中输入的预期干净输出。</p></li>\n</ul>\n</dd>\n</dl>\n<p>例如，以下代码测试 <code class=\"docutils literal notranslate\">EmailField</code> 接受 <code class=\"docutils literal notranslate\">a&#64;a.com</code> 作为有效的电子邮件地址，但拒绝 <code class=\"docutils literal notranslate\">aaa</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=\"bp\">self</span><span class=\"o\">.</span>assertFieldOutput<span class=\"p\">(</span>EmailField<span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;a@a.com&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;a@a.com&#39;</span><span class=\"p\">},</span> <span class=\"p\">{</span><span class=\"s1\">&#39;aaa&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;Enter a valid email address.&#39;</span><span class=\"p\">]})</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertFormError\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertFormError</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">form</em>, <em class=\"sig-param\">field</em>, <em class=\"sig-param\">errors</em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertFormError\"><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\">response</code> must be a response instance returned by the\n<a class=\"reference internal\" href=\"#django.test.Response\" title=\"django.test.Response\"><code class=\"xref py py-class docutils literal notranslate\">test client</code></a>.</p>\n<p><code class=\"docutils literal notranslate\">form</code> is the name the <code class=\"docutils literal notranslate\">Form</code> instance was given in the template\ncontext of the response.</p>\n<p><code class=\"docutils literal notranslate\">field</code> 是表单中要检查的字段名。如果 <code class=\"docutils literal notranslate\">field</code> 的值为 <code class=\"docutils literal notranslate\">None</code>，则会检查非字段错误（可以通过 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/forms/api/#django.forms.Form.non_field_errors\" title=\"django.forms.Form.non_field_errors\"><code class=\"xref py py-meth docutils literal notranslate\">form.non_field_errors()</code></a>）。</p>\n<p><code class=\"docutils literal notranslate\">errors</code> 是一个错误字符串，或一个错误字符串列表，是表单验证的结果。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertFormsetError\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertFormsetError</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">formset</em>, <em class=\"sig-param\">form_index</em>, <em class=\"sig-param\">field</em>, <em class=\"sig-param\">errors</em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertFormsetError\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言 <code class=\"docutils literal notranslate\">formset</code> 在渲染时，会引发所提供的错误列表。</p>\n<p><code class=\"docutils literal notranslate\">response</code> must be a response instance returned by the\n<a class=\"reference internal\" href=\"#django.test.Response\" title=\"django.test.Response\"><code class=\"xref py py-class docutils literal notranslate\">test client</code></a>.</p>\n<p><code class=\"docutils literal notranslate\">formset</code> is the name the <code class=\"docutils literal notranslate\">Formset</code> instance was given in the template\ncontext of the response.</p>\n<p><code class=\"docutils literal notranslate\">form_index</code> 是 <code class=\"docutils literal notranslate\">Formset</code> 中表单的编号。 如果 <code class=\"docutils literal notranslate\">form_index</code> 的值为 <code class=\"docutils literal notranslate\">None</code>，则将检查非表单错误（可以通过 <code class=\"docutils literal notranslate\">formset.non_form_errors()</code> 访问的错误）。</p>\n<p><code class=\"docutils literal notranslate\">field</code> 是表单中要检查的字段名。如果 <code class=\"docutils literal notranslate\">field</code> 的值为 <code class=\"docutils literal notranslate\">None</code>，则会检查非字段错误（可以通过 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/forms/api/#django.forms.Form.non_field_errors\" title=\"django.forms.Form.non_field_errors\"><code class=\"xref py py-meth docutils literal notranslate\">form.non_field_errors()</code></a>）。</p>\n<p><code class=\"docutils literal notranslate\">errors</code> 是一个错误字符串，或一个错误字符串列表，是表单验证的结果。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertContains\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertContains</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">text</em>, <em class=\"sig-param\">count<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">status_code<span class=\"o\">=</span><span class=\"default_value\">200</span></em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">html<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertContains\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Asserts that a <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">response</code></a> produced the\ngiven <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse.status_code\" title=\"django.http.HttpResponse.status_code\"><code class=\"xref py py-attr docutils literal notranslate\">status_code</code></a> and that <code class=\"docutils literal notranslate\">text</code>\nappears in its <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse.content\" title=\"django.http.HttpResponse.content\"><code class=\"xref py py-attr docutils literal notranslate\">content</code></a>. If <code class=\"docutils literal notranslate\">count</code>\nis provided, <code class=\"docutils literal notranslate\">text</code> must occur exactly <code class=\"docutils literal notranslate\">count</code> times in the response.</p>\n<p>将 <code class=\"docutils literal notranslate\">html</code> 设置为 <code class=\"docutils literal notranslate\">True</code>，将 <code class=\"docutils literal notranslate\">text</code> 作为 HTML 处理。与响应内容的比较将基于 HTML 语义，而不是逐个字符的平等。在大多数情况下，空格会被忽略，属性排序并不重要。详见 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\" title=\"django.test.SimpleTestCase.assertHTMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertHTMLEqual()</code></a>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertNotContains\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertNotContains</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">text</em>, <em class=\"sig-param\">status_code<span class=\"o\">=</span><span class=\"default_value\">200</span></em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">html<span class=\"o\">=</span><span class=\"default_value\">False</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertNotContains\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Asserts that a <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">response</code></a> produced the\ngiven <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse.status_code\" title=\"django.http.HttpResponse.status_code\"><code class=\"xref py py-attr docutils literal notranslate\">status_code</code></a> and that <code class=\"docutils literal notranslate\">text</code> does\n<em>not</em> appear in its <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse.content\" title=\"django.http.HttpResponse.content\"><code class=\"xref py py-attr docutils literal notranslate\">content</code></a>.</p>\n<p>将 <code class=\"docutils literal notranslate\">html</code> 设置为 <code class=\"docutils literal notranslate\">True</code>，将 <code class=\"docutils literal notranslate\">text</code> 作为 HTML 处理。与响应内容的比较将基于 HTML 语义，而不是逐个字符的平等。在大多数情况下，空格会被忽略，属性排序并不重要。详见 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\" title=\"django.test.SimpleTestCase.assertHTMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertHTMLEqual()</code></a>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertTemplateUsed\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertTemplateUsed</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">template_name</em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">count<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertTemplateUsed\"><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\">response</code> must be a response instance returned by the\n<a class=\"reference internal\" href=\"#django.test.Response\" title=\"django.test.Response\"><code class=\"xref py py-class docutils literal notranslate\">test client</code></a>.</p>\n<p><code class=\"docutils literal notranslate\">template_name``应当是一个字符串，如</code>'admin/index.html'<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>。</p>\n<p>The <code class=\"docutils literal notranslate\">count</code> argument is an integer indicating the number of times the\ntemplate should be rendered. Default is <code class=\"docutils literal notranslate\">None</code>, meaning that the template\nshould be rendered one or more times.</p>\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=\"k\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>assertTemplateUsed<span class=\"p\">(</span><span class=\"s1\">&#39;index.html&#39;</span><span class=\"p\">):</span>\n    render_to_string<span class=\"p\">(</span><span class=\"s1\">&#39;index.html&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>assertTemplateUsed<span class=\"p\">(</span>template_name<span class=\"o\">=</span><span class=\"s1\">&#39;index.html&#39;</span><span class=\"p\">):</span>\n    render_to_string<span class=\"p\">(</span><span class=\"s1\">&#39;index.html&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertTemplateNotUsed\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertTemplateNotUsed</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">template_name</em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertTemplateNotUsed\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言给定名称的模板在渲染响应时 <em>没有</em> 被使用。</p>\n<p>你可以用 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertTemplateUsed\" title=\"django.test.SimpleTestCase.assertTemplateUsed\"><code class=\"xref py py-meth docutils literal notranslate\">assertTemplateUsed()</code></a> 一样的方式将其作为上下文管理器。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertURLEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertURLEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">url1</em>, <em class=\"sig-param\">url2</em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertURLEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言两个 URL 是相同的，忽略查询字符串参数的顺序，但同名参数除外。例如，<code class=\"docutils literal notranslate\">/path/?x=1&amp;y=2</code> 等于 <code class=\"docutils literal notranslate\">/path/?y=2&amp;x=1</code>，但 <code class=\"docutils literal notranslate\">/path/?a=1&amp;a=2</code> 不等于 <code class=\"docutils literal notranslate\">/path/?a=2&amp;a=1</code>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertRedirects\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertRedirects</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">response</em>, <em class=\"sig-param\">expected_url</em>, <em class=\"sig-param\">status_code<span class=\"o\">=</span><span class=\"default_value\">302</span></em>, <em class=\"sig-param\">target_status_code<span class=\"o\">=</span><span class=\"default_value\">200</span></em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em>, <em class=\"sig-param\">fetch_redirect_response<span class=\"o\">=</span><span class=\"default_value\">True</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertRedirects\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Asserts that the <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\">response</code></a> returned a\n<a class=\"reference internal\" href=\"/zh-hans/4.0/ref/request-response/#django.http.HttpResponse.status_code\" title=\"django.http.HttpResponse.status_code\"><code class=\"xref py py-attr docutils literal notranslate\">status_code</code></a> redirect status, redirected\nto <code class=\"docutils literal notranslate\">expected_url</code> (including any <code class=\"docutils literal notranslate\">GET</code> data), and that the final page\nwas received with <code class=\"docutils literal notranslate\">target_status_code</code>.</p>\n<p>如果你的请求使用了 <code class=\"docutils literal notranslate\">follow</code> 参数，<code class=\"docutils literal notranslate\">expected_url</code> 和 <code class=\"docutils literal notranslate\">target_status_code</code> 将是重定向链最后一点的网址和状态码。</p>\n<p>如果 <code class=\"docutils literal notranslate\">fetch_redirect_response</code> 为 <code class=\"docutils literal notranslate\">False</code>，则最终页面不会被加载。由于测试客户端不能获取外部 URL，所以如果 <code class=\"docutils literal notranslate\">expected_url</code> 不是 Django 应用的一部分，这一点就特别有用。</p>\n<p>在两个 URL 之间进行比较时，可以正确处理协议。如果在我们被重定向到的位置没有指定任何协议，则使用原始请求的协议。如果存在，<code class=\"docutils literal notranslate\">expected_url</code> 中的协议就是用来进行比较的。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertHTMLEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertHTMLEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">html1</em>, <em class=\"sig-param\">html2</em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言字符串 <code class=\"docutils literal notranslate\">html1</code> 和 <code class=\"docutils literal notranslate\">html2</code> 相等。比较是基于 HTML 语义的。比较时考虑到以下因素：</p>\n<ul class=\"simple\">\n<li><p>HTML 标签前后的空白会被忽略。</p></li>\n<li><p>所有类型的空白都被认为是等价的。</p></li>\n<li><p>所有打开的标签都是隐式关闭的，例如当周围的标签关闭或 HTML 文档结束时。</p></li>\n<li><p>空标签相当于其自动闭合版。</p></li>\n<li><p>HTML 元素的属性排序并不重要。</p></li>\n<li><p>Boolean attributes (like <code class=\"docutils literal notranslate\">checked</code>) without an argument are equal to\nattributes that equal in name and value (see the examples).</p></li>\n<li><p>引用同一字符的文本、字符引用和实体引用是等价的。</p></li>\n</ul>\n<p>下面的例子是有效的测试，并且没有引起任何 <code class=\"docutils literal notranslate\">AssertionError</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=\"bp\">self</span><span class=\"o\">.</span>assertHTMLEqual<span class=\"p\">(</span>\n    <span class=\"s1\">&#39;&lt;p&gt;Hello &lt;b&gt;&amp;#x27;world&amp;#x27;!&lt;/p&gt;&#39;</span><span class=\"p\">,</span>\n    <span class=\"sd\">&#39;&#39;&#39;&lt;p&gt;</span>\n<span class=\"sd\">        Hello   &lt;b&gt;&amp;#39;world&amp;#39;! &lt;/b&gt;</span>\n<span class=\"sd\">    &lt;/p&gt;&#39;&#39;&#39;</span>\n<span class=\"p\">)</span>\n<span class=\"bp\">self</span><span class=\"o\">.</span>assertHTMLEqual<span class=\"p\">(</span>\n    <span class=\"s1\">&#39;&lt;input type=&quot;checkbox&quot; checked=&quot;checked&quot; id=&quot;id_accept_terms&quot; /&gt;&#39;</span><span class=\"p\">,</span>\n    <span class=\"s1\">&#39;&lt;input id=&quot;id_accept_terms&quot; type=&quot;checkbox&quot; checked&gt;&#39;</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">html1</code> 和 <code class=\"docutils literal notranslate\">html2</code> 必须包含 HTML。如果其中一个不能被解析，将产生一个 <code class=\"docutils literal notranslate\">AssertionError</code>。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</p>\n<aside class=\"version-note version-changed\" data-version=\"4.0\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 4.0</p><p>In older versions, any attribute (not only boolean attributes) without\na value was considered equal to an attribute with the same name and\nvalue.</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertHTMLNotEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertHTMLNotEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">html1</em>, <em class=\"sig-param\">html2</em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertHTMLNotEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言字符串 <code class=\"docutils literal notranslate\">html1</code> 和 <code class=\"docutils literal notranslate\">html2</code> <em>不</em> 相等。比较是基于 HTML 语义的。详见 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\" title=\"django.test.SimpleTestCase.assertHTMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertHTMLEqual()</code></a>。</p>\n<p><code class=\"docutils literal notranslate\">html1</code> 和 <code class=\"docutils literal notranslate\">html2</code> 必须包含 HTML。如果其中一个不能被解析，将产生一个 <code class=\"docutils literal notranslate\">AssertionError</code>。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertXMLEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertXMLEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">xml1</em>, <em class=\"sig-param\">xml2</em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertXMLEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言字符串 <code class=\"docutils literal notranslate\">xml1</code> 和 <code class=\"docutils literal notranslate\">xml2</code> 相等。比较是基于 XML 语义的。与 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\" title=\"django.test.SimpleTestCase.assertHTMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertHTMLEqual()</code></a> 类似，比较是在解析内容上进行的，因此只考虑语义差异，而不是语法差异。当任何参数中传递了无效的 XML 时，即使两个字符串相同，也总是会引发一个 <code class=\"docutils literal notranslate\">AssertionError</code>。</p>\n<p>忽略 XML 声明、文档类型、处理指令和注释。只有根元素和它的子元素被比较。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertXMLNotEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertXMLNotEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">xml1</em>, <em class=\"sig-param\">xml2</em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertXMLNotEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言字符串 <code class=\"docutils literal notranslate\">xml1</code> 和 <code class=\"docutils literal notranslate\">xml2</code> <em>不</em> 相等。比较是基于 XML 语义的，参见 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertXMLEqual\" title=\"django.test.SimpleTestCase.assertXMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertXMLEqual()</code></a>。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertInHTML\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertInHTML</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">needle</em>, <em class=\"sig-param\">haystack</em>, <em class=\"sig-param\">count<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">msg_prefix<span class=\"o\">=</span><span class=\"default_value\">''</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertInHTML\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言 HTML 片段 <code class=\"docutils literal notranslate\">needle</code> 包含在 <code class=\"docutils literal notranslate\">haystack</code> 中。</p>\n<p>如果指定了 <code class=\"docutils literal notranslate\">count</code> 整数参数，则将严格核查 <code class=\"docutils literal notranslate\">needle</code> 的出现次数。</p>\n<p>在大多数情况下，空白是被忽略的，属性排序并不重要。参见 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertHTMLEqual\" title=\"django.test.SimpleTestCase.assertHTMLEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertHTMLEqual()</code></a> 以了解更多细节。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertJSONEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertJSONEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">raw</em>, <em class=\"sig-param\">expected_data</em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertJSONEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言 JSON 片段 <code class=\"docutils literal notranslate\">raw</code> 和 <code class=\"docutils literal notranslate\">expected_data</code> 相等。通常的 JSON 非显性空格规则适用，因为重量级是委托给 <a class=\"reference external\" href=\"https://docs.python.org/3/library/json.html#module-json\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">json</code></a> 库的。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.SimpleTestCase.assertJSONNotEqual\">\n<span class=\"sig-prename descclassname\">SimpleTestCase.</span><span class=\"sig-name descname\">assertJSONNotEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">raw</em>, <em class=\"sig-param\">expected_data</em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.SimpleTestCase.assertJSONNotEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言 JSON 片段 <code class=\"docutils literal notranslate\">raw</code> 和 <code class=\"docutils literal notranslate\">expected_data</code> <em>不</em> 相等。详见 <a class=\"reference internal\" href=\"#django.test.SimpleTestCase.assertJSONEqual\" title=\"django.test.SimpleTestCase.assertJSONEqual\"><code class=\"xref py py-meth docutils literal notranslate\">assertJSONEqual()</code></a>。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase.assertQuerysetEqual\">\n<span class=\"sig-prename descclassname\">TransactionTestCase.</span><span class=\"sig-name descname\">assertQuerysetEqual</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">qs</em>, <em class=\"sig-param\">values</em>, <em class=\"sig-param\">transform<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">ordered<span class=\"o\">=</span><span class=\"default_value\">True</span></em>, <em class=\"sig-param\">msg<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase.assertQuerysetEqual\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言一个查询集 <code class=\"docutils literal notranslate\">qs</code> 与一个特定的可迭代对象 <code class=\"docutils literal notranslate\">values</code> 的值匹配。</p>\n<p>如果提供了 <code class=\"docutils literal notranslate\">transform</code>，<code class=\"docutils literal notranslate\">values</code> 将与应用 <code class=\"docutils literal notranslate\">transform</code> 于 <code class=\"docutils literal notranslate\">qs</code> 而产生的列表中每个成员进行比较。</p>\n<p>默认情况下，比较也是依赖于顺序的。如果 <code class=\"docutils literal notranslate\">qs</code> 不提供隐式排序，你可以将 <code class=\"docutils literal notranslate\">ordered</code> 参数设置为 <code class=\"docutils literal notranslate\">False</code>，这将使比较变成 <code class=\"docutils literal notranslate\">collections.Counter</code> 比较。如果顺序是未定义的（如果给定的 <code class=\"docutils literal notranslate\">qs</code> 不是有序的，并且比较的对象是一个以上的有序值），会产生一个 <code class=\"docutils literal notranslate\">ValueError</code>。</p>\n<p>错误时的输出可以用 <code class=\"docutils literal notranslate\">msg</code> 参数自定义。</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\">transform</code> 参数的默认值改为 <code class=\"docutils literal notranslate\">None</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>增加了对查询集之间直接比较的支持。</p>\n</aside>\n<aside class=\"version-note version-deprecated\" data-version=\"3.2\" role=\"note\">\n<p class=\"version-note-title\">Deprecated since Django 3.2</p><p><span class=\"versionmodified deprecated\">Deprecated since version 3.2: </span>如果没有提供 <code class=\"docutils literal notranslate\">transform</code>，并且 <code class=\"docutils literal notranslate\">values</code> 是一个字符串列表，它将被比作一个对 <code class=\"docutils literal notranslate\">qs</code> 的每个成员应用 <code class=\"docutils literal notranslate\">repr()</code> 产生的列表。这一行为已被废弃，并将在 Django 4.1 中被移除。如果你需要它，可以明确地将 <code class=\"docutils literal notranslate\">transform</code> 设置为 <code class=\"docutils literal notranslate\">repr</code>。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.test.TransactionTestCase.assertNumQueries\">\n<span class=\"sig-prename descclassname\">TransactionTestCase.</span><span class=\"sig-name descname\">assertNumQueries</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">num</em>, <em class=\"sig-param\">func</em>, <em class=\"sig-param\"><span class=\"o\">*</span>args</em>, <em class=\"sig-param\"><span class=\"o\">**</span>kwargs</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.TransactionTestCase.assertNumQueries\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>断言当 <code class=\"docutils literal notranslate\">func</code> 与 <code class=\"docutils literal notranslate\">*args</code> 和 <code class=\"docutils literal notranslate\">**kwargs</code> 一起调用时，会执行 <code class=\"docutils literal notranslate\">num</code> 次数据库查询。</p>\n<p>如果 <code class=\"docutils literal notranslate\">kwargs</code> 中存在 <code class=\"docutils literal notranslate\">&quot;using&quot;</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=\"bp\">self</span><span class=\"o\">.</span>assertNumQueries<span class=\"p\">(</span><span class=\"mi\">7</span><span class=\"p\">,</span> using<span class=\"o\">=</span><span class=\"s1\">&#39;non_default_db&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你想调用一个带有 <code class=\"docutils literal notranslate\">using</code> 参数的函数，你可以通过用 <code class=\"docutils literal notranslate\">lambda</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=\"bp\">self</span><span class=\"o\">.</span>assertNumQueries<span class=\"p\">(</span><span class=\"mi\">7</span><span class=\"p\">,</span> <span class=\"k\">lambda</span><span class=\"p\">:</span> my_function<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"mi\">7</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><span class=\"k\">with</span> <span class=\"bp\">self</span><span class=\"o\">.</span>assertNumQueries<span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">):</span>\n    Person<span class=\"o\">.</span>objects<span class=\"o\">.</span>create<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Aaron&quot;</span><span class=\"p\">)</span>\n    Person<span class=\"o\">.</span>objects<span class=\"o\">.</span>create<span class=\"p\">(</span>name<span class=\"o\">=</span><span class=\"s2\">&quot;Daniel&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n<section id=\"tagging-tests\">\n<span id=\"topics-tagging-tests\"></span><h3>标记测试<a class=\"heading-anchor\" href=\"#tagging-tests\"><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.test</span> <span class=\"kn\">import</span> tag\n\n<span class=\"k\">class</span> <span class=\"nc\">SampleTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"nd\">@tag</span><span class=\"p\">(</span><span class=\"s1\">&#39;fast&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_fast</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"o\">...</span>\n\n    <span class=\"nd\">@tag</span><span class=\"p\">(</span><span class=\"s1\">&#39;slow&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_slow</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"o\">...</span>\n\n    <span class=\"nd\">@tag</span><span class=\"p\">(</span><span class=\"s1\">&#39;slow&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;core&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_slow_but_core</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"o\">...</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><span class=\"nd\">@tag</span><span class=\"p\">(</span><span class=\"s1\">&#39;slow&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;core&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">class</span> <span class=\"nc\">SampleTestCase</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"o\">...</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><span class=\"nd\">@tag</span><span class=\"p\">(</span><span class=\"s1\">&#39;foo&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">class</span> <span class=\"nc\">SampleTestCaseChild</span><span class=\"p\">(</span>SampleTestCase<span class=\"p\">):</span>\n\n    <span class=\"nd\">@tag</span><span class=\"p\">(</span><span class=\"s1\">&#39;bar&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">SampleTestCaseChild.test</code> 将用 <code class=\"docutils literal notranslate\">'slow'</code>、<code class=\"docutils literal notranslate\">'core'</code>、<code class=\"docutils literal notranslate\">'bar'</code> 和 <code class=\"docutils literal notranslate\">'foo'</code> 来标注。</p>\n<p>然后你可以选择要运行的测试。例如，只运行快速测试：</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-2-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code><span class=\"gp\">$ </span>./manage.py <span class=\"nb\">test</span> --tag<span class=\"o\">=</span>fast\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-2-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</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=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> manage.py test --tag=fast\n</code></pre></div></div></div>\n<p>或者运行快速测试和核心测试（即使它很慢）：</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-3-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code><span class=\"gp\">$ </span>./manage.py <span class=\"nb\">test</span> --tag<span class=\"o\">=</span>fast --tag<span class=\"o\">=</span>core\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-3-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</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=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> manage.py test --tag=fast --tag=core\n</code></pre></div></div></div>\n<p>你也可以通过标签来排除测试。如果要运行不慢的核心测试：</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-4-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code><span class=\"gp\">$ </span>./manage.py <span class=\"nb\">test</span> --tag<span class=\"o\">=</span>core --exclude-tag<span class=\"o\">=</span>slow\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-4-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</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=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> manage.py test --tag=core --exclude-tag=slow\n</code></pre></div></div></div>\n<p><code class=\"xref std std-option docutils literal notranslate\">test --exclud-tag</code> 优先于 <a class=\"reference internal\" href=\"/zh-hans/4.0/ref/django-admin/#cmdoption-test-tag\"><code class=\"xref std std-option docutils literal notranslate\">test --tag</code></a>，所以如果一个测试有两个标签，你选择了其中一个而排除了另一个，测试就不会被运行。</p>\n</section>\n</section>\n<section id=\"testing-asynchronous-code\">\n<span id=\"async-tests\"></span><h2>测试异步代码<a class=\"heading-anchor\" href=\"#testing-asynchronous-code\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果你只是想测试异步视图的输出，标准测试客户端将在自己的异步循环中运行它们，而不需要你做任何额外的工作。</p>\n<p>但是，如果你想为 Django 项目编写完全异步的测试，你需要考虑到几个问题。</p>\n<p>首先，你的测试必须是测试类上的 <code class=\"docutils literal notranslate\">async def</code> 方法（为了给它们一个异步的上下文）。Django 会自动检测到任何 <code class=\"docutils literal notranslate\">async def</code> 的测试，并将它们封装在自己的事件循环中运行。</p>\n<p>如果你从一个异步函数进行测试，你也必须使用异步测试客户端。这在任何测试中都可以作为 <code class=\"docutils literal notranslate\">django.test.AsyncClient</code> 或 <code class=\"docutils literal notranslate\">self.async_client</code> 使用。</p>\n<p><code class=\"docutils literal notranslate\">AsyncClient</code> 具有与同步（普通）测试客户端相同的方法和签名，但有两个例外：</p>\n<ul>\n<li><p>不支持 <code class=\"docutils literal notranslate\">follow</code> 参数。</p></li>\n<li><p>作为 <code class=\"docutils literal notranslate\">extra</code> 关键字参数传递的头信息不应该有同步客户端所要求的 <code class=\"docutils literal notranslate\">HTTP_</code> 前缀（参见 <a class=\"reference internal\" href=\"#django.test.Client.get\" title=\"django.test.Client.get\"><code class=\"xref py py-meth docutils literal notranslate\">Client.get()</code></a>）。例如，下面是如何设置 HTTP <code class=\"docutils literal notranslate\">Accept</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=\"gp\">&gt;&gt;&gt; </span>c <span class=\"o\">=</span> AsyncClient<span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>c<span class=\"o\">.</span>get<span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"s1\">&#39;/customers/details/&#39;</span><span class=\"p\">,</span>\n<span class=\"gp\">... </span>    <span class=\"p\">{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;fred&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;age&#39;</span><span class=\"p\">:</span> <span class=\"mi\">7</span><span class=\"p\">},</span>\n<span class=\"gp\">... </span>    ACCEPT<span class=\"o\">=</span><span class=\"s1\">&#39;application/json&#39;</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span>\n</code></pre></div>\n</li>\n</ul>\n<p>使用 <code class=\"docutils literal notranslate\">AsyncClient</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\">async</span> <span class=\"k\">def</span> <span class=\"nf\">test_my_thing</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    response <span class=\"o\">=</span> <span class=\"k\">await</span> <span class=\"bp\">self</span><span class=\"o\">.</span>async_client<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s1\">&#39;/some-url/&#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>异步客户端也可以调用同步视图；它通过 Django 的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/async/\"><span class=\"doc\">异步请求路径</span></a> 运行，它支持这两种方式。任何通过 <code class=\"docutils literal notranslate\">AsyncClient</code> 调用的视图都会得到一个 <code class=\"docutils literal notranslate\">ASGIRequest</code> 对象作为它的 <code class=\"docutils literal notranslate\">request</code>，而不是普通客户端创建的 <code class=\"docutils literal notranslate\">WSGIRequest</code>。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>如果你使用的是测试装饰器，它们必须是异步兼容的，以确保它们正确工作。Django 内置的装饰器会正常工作，但第三方的装饰器可能会出现无法执行的情况（它们会“包装”执行流程中错误的部分，而不是你的测试）。</p>\n<p>如果你需要使用这些装饰器，那么你应该用 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/async/#asgiref.sync.async_to_sync\" title=\"asgiref.sync.async_to_sync\"><code class=\"xref py py-func docutils literal notranslate\">async_to_sync()</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><span class=\"kn\">from</span> <span class=\"nn\">asgiref.sync</span> <span class=\"kn\">import</span> async_to_sync\n<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\">MyTests</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n\n    <span class=\"nd\">@mock</span><span class=\"o\">.</span>patch<span class=\"p\">(</span><span class=\"o\">...</span><span class=\"p\">)</span>\n    <span class=\"nd\">@async_to_sync</span>\n    <span class=\"k\">async</span> <span class=\"k\">def</span> <span class=\"nf\">test_my_thing</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n</aside>\n</section>\n<section id=\"email-services\">\n<span id=\"topics-testing-email\"></span><h2>邮件服务<a class=\"heading-anchor\" href=\"#email-services\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果你的任何 Django 视图使用 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/email/\"><span class=\"doc\">Django 的邮件功能</span></a> 发送电子邮件，你可能不想每次使用该视图运行测试时都发送电子邮件。出于这个原因，Django 的测试运行器会自动将所有 Django 发送的邮件重定向到一个虚拟的发件箱。这让你可以测试发送邮件的每一个方面——从发送邮件的数量到每封邮件的内容——而不用实际发送邮件。</p>\n<p>测试运行器通过透明的将正常的邮件后端替换为测试后端来实现。（别担心——这对 Django 之外的其他邮件发送器没有影响，比如你机器的邮件服务器，如果你正在运行一个的话。）</p>\n<dl class=\"py data\">\n<dt class=\"sig sig-object py\" id=\"django.core.mail.django.core.mail.outbox\">\n<span class=\"sig-prename descclassname\">django.core.mail.</span><span class=\"sig-name descname\">outbox</span><a class=\"heading-anchor\" href=\"#django.core.mail.django.core.mail.outbox\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>在测试运行过程中，每一封发出的邮件都会保存在 <code class=\"docutils literal notranslate\">django.core.mail.outbox</code> 中。这是所有已经发送的 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/email/#django.core.mail.EmailMessage\" title=\"django.core.mail.EmailMessage\"><code class=\"xref py py-class docutils literal notranslate\">EmailMessage</code></a> 实例的列表。 <code class=\"docutils literal notranslate\">outbox</code> 属性是一个特殊的属性，只有在使用 <code class=\"docutils literal notranslate\">locmem</code> 邮件后端时才会创建。它通常不作为 <a class=\"reference internal\" href=\"/zh-hans/4.0/topics/email/#module-django.core.mail\" title=\"django.core.mail: Helpers to easily send email.\"><code class=\"xref py py-mod docutils literal notranslate\">django.core.mail</code></a> 模块的一部分存在，你也不能直接导入它。下面的代码展示了如何正确访问这个属性。</p>\n<p>下面是一个检查 <code class=\"docutils literal notranslate\">django.core.mail.outbox</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.core</span> <span class=\"kn\">import</span> mail\n<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\">EmailTest</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_send_email</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Send message.</span>\n        mail<span class=\"o\">.</span>send_mail<span class=\"p\">(</span>\n            <span class=\"s1\">&#39;Subject here&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Here is the message.&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;from@example.com&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"s1\">&#39;to@example.com&#39;</span><span class=\"p\">],</span>\n            fail_silently<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span>\n        <span class=\"p\">)</span>\n\n        <span class=\"c1\"># Test that one message has been sent.</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span><span class=\"nb\">len</span><span class=\"p\">(</span>mail<span class=\"o\">.</span>outbox<span class=\"p\">),</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Verify that the subject of the first message is correct.</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertEqual<span class=\"p\">(</span>mail<span class=\"o\">.</span>outbox<span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span>subject<span class=\"p\">,</span> <span class=\"s1\">&#39;Subject here&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>正如 <a class=\"reference internal\" href=\"#emptying-test-outbox\"><span class=\"std std-ref\">之前</span></a>，在 Django <code class=\"docutils literal notranslate\">*TestCase</code> 中的每个测试开始时，测试发件箱都会被清空。要手动清空发件箱，将空列表分配给 <code class=\"docutils literal notranslate\">mail.outbox</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.core</span> <span class=\"kn\">import</span> mail\n\n<span class=\"c1\"># Empty the test outbox</span>\nmail<span class=\"o\">.</span>outbox <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</code></pre></div>\n</section>\n<section id=\"management-commands\">\n<span id=\"topics-testing-management-commands\"></span><h2>管理命令<a class=\"heading-anchor\" href=\"#management-commands\"><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/4.0/ref/django-admin/#django.core.management.call_command\" title=\"django.core.management.call_command\"><code class=\"xref py py-func docutils literal notranslate\">call_command()</code></a> 函数来测试。输出可以重定向到 <code class=\"docutils literal notranslate\">StringIO</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\">io</span> <span class=\"kn\">import</span> StringIO\n<span class=\"kn\">from</span> <span class=\"nn\">django.core.management</span> <span class=\"kn\">import</span> call_command\n<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\">ClosepollTest</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_command_output</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        out <span class=\"o\">=</span> StringIO<span class=\"p\">()</span>\n        call_command<span class=\"p\">(</span><span class=\"s1\">&#39;closepoll&#39;</span><span class=\"p\">,</span> stdout<span class=\"o\">=</span>out<span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span>assertIn<span class=\"p\">(</span><span class=\"s1\">&#39;Expected output&#39;</span><span class=\"p\">,</span> out<span class=\"o\">.</span>getvalue<span class=\"p\">())</span>\n</code></pre></div>\n</section>\n<section id=\"skipping-tests\">\n<span id=\"id3\"></span><h2>忽略测试<a class=\"heading-anchor\" href=\"#skipping-tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>unittest 库提供了 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.skipIf\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">&#64;skipIf</code></a> 和 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.skipUnless\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">&#64;skipUnless</code></a> 装饰器，允许你跳过测试，如果你事先知道这些测试在某些条件下会失败。</p>\n<p>例如，如果你的测试需要一个特定的可选库才能成功，你可以用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/unittest.html#unittest.skipIf\" title=\"(in Python v3.14)\"><code class=\"xref py py-func docutils literal notranslate\">&#64;skipIf</code></a> 来装饰测试用例。然后，测试运行器将报告测试没有被执行以及原因，而不是测试失败或完全省略测试。</p>\n<p>为了补充这些测试跳过行为，Django 提供了两个额外的跳过装饰器。这些装饰器不是测试一个通用的布尔值，而是检查数据库的能力，如果数据库不支持一个特定的命名特性，则跳过测试。</p>\n<p>装饰器使用一个字符串标识符来描述数据库特征。这个字符串对应于数据库连接特征类的属性。参见 <a class=\"extlink-source reference external\" href=\"https://github.com/django/django/blob/stable/4.0.x/django/db/backends/base/features.py\">django.db.backends.base.features.BaseDatabaseFeatures 类</a> 以获得可作为跳过测试基础的数据库特征的完整列表。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.skipIfDBFeature\">\n<span class=\"sig-name descname\">skipIfDBFeature</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">*</span>feature_name_strings</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.skipIfDBFeature\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果支持某个命名的数据库功能，则跳过装饰测试或 <code class=\"docutils literal notranslate\">TestCase</code>。</p>\n<p>例如，如果数据库支持事务，下面的测试将不会被执行（例如，在PostgreSQL 下，它将 <em>不</em> 会运行，但在 MySQL 的 MyISAM 表下却可以）：</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\">MyTests</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"nd\">@skipIfDBFeature</span><span class=\"p\">(</span><span class=\"s1\">&#39;supports_transactions&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_transaction_behavior</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ... conditional test code</span>\n        <span class=\"k\">pass</span>\n</code></pre></div>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.test.skipUnlessDBFeature\">\n<span class=\"sig-name descname\">skipUnlessDBFeature</span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"o\">*</span>feature_name_strings</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.test.skipUnlessDBFeature\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果 <em>不</em> 支持某个命名的数据库功能，则跳过装饰测试或 <code class=\"docutils literal notranslate\">TestCase</code>。</p>\n<p>例如，接下来的测试仅在支持事务的数据库下执行(如：可以是PostgreSQL，但不可以是使用MyISAM数据库引擎的MySQL):</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\">MyTests</span><span class=\"p\">(</span>TestCase<span class=\"p\">):</span>\n    <span class=\"nd\">@skipUnlessDBFeature</span><span class=\"p\">(</span><span class=\"s1\">&#39;supports_transactions&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span> <span class=\"nf\">test_transaction_behavior</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># ... conditional test code</span>\n        <span class=\"k\">pass</span>\n</code></pre></div>\n</section>","rootId":"testing-tools","toc":[{"title":"测试客户端","anchor":"the-test-client","children":[{"title":"概述和一个简单的例子","anchor":"overview-and-a-quick-example","children":[]},{"title":"发出请求","anchor":"making-requests","children":[]},{"title":"测试响应","anchor":"testing-responses","children":[]},{"title":"例外","anchor":"exceptions","children":[]},{"title":"持久状态","anchor":"persistent-state","children":[]},{"title":"设置语言","anchor":"setting-the-language","children":[]},{"title":"例如","anchor":"example","children":[]}]},{"title":"提供的测试用例类","anchor":"provided-test-case-classes","children":[{"title":"SimpleTestCase","anchor":"simpletestcase","children":[]},{"title":"TransactionTestCase","anchor":"transactiontestcase","children":[]},{"title":"TestCase","anchor":"testcase","children":[]},{"title":"LiveServerTestCase","anchor":"liveservertestcase","children":[]}]},{"title":"测试用例特性","anchor":"test-cases-features","children":[{"title":"默认测试客户端","anchor":"default-test-client","children":[]},{"title":"自定义测试客户端","anchor":"customizing-the-test-client","children":[]},{"title":"辅助工具加载","anchor":"fixture-loading","children":[]},{"title":"URLconf 配置","anchor":"urlconf-configuration","children":[]},{"title":"多数据库支持","anchor":"multi-database-support","children":[]},{"title":"覆盖配置","anchor":"overriding-settings","children":[]},{"title":"清空测试发件箱","anchor":"emptying-the-test-outbox","children":[]},{"title":"断言","anchor":"assertions","children":[]},{"title":"标记测试","anchor":"tagging-tests","children":[]}]},{"title":"测试异步代码","anchor":"testing-asynchronous-code","children":[]},{"title":"邮件服务","anchor":"email-services","children":[]},{"title":"管理命令","anchor":"management-commands","children":[]},{"title":"忽略测试","anchor":"skipping-tests","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/4.0/topics/"},{"docname":"topics/testing/index","title":"Django 中的测试","url":"/zh-hans/4.0/topics/testing/"}],"prev":{"docname":"topics/testing/overview","title":"编写并运行测试","url":"/zh-hans/4.0/topics/testing/overview/"},"next":{"docname":"topics/testing/advanced","title":"进阶测试主题","url":"/zh-hans/4.0/topics/testing/advanced/"},"formats":{"html":"/zh-hans/4.0/topics/testing/tools/","markdown":"/zh-hans/4.0/topics/testing/tools.md","json":"/zh-hans/4.0/topics/testing/tools.json"},"source":"https://github.com/django/django/blob/stable/4.0.x/docs/topics/testing/tools.txt","official":"https://docs.djangoproject.com/zh-hans/4.0/topics/testing/tools/","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"]}