单元测试

最后更新于:2022-04-01 04:07:15

# 单元测试 也许你经常需要对你的的应用进行单元测试或者仅仅检查 Python session 的输出。理论上讲这是很简单的,你可以伪造一个环境,通过一个假的 start_response 遍历应用,但是这里还有一个更好的方法。 ### Diving In Werkzeug 提供了一个 Client 对象,可以传入一个 WSGI 应用(可选传入一个 response),通过这个你可以向应用发出一个虚拟请求。 用三个参数调用一个 response: 应用迭代器、状态和一个 headers。默认 response 返回一个元组。因为 response 对象有相同的签名,所以你可以像使用 response 一样使用他们。通过这样一种方式进行测试功能是很理想的。 ~~~ >>> from werkzeug.test import Client >>> from werkzeug.testapp import test_app >>> from werkzeug.wrappers import BaseResponse >>> c = Client(test_app, BaseResponse) >>> resp = c.get('/') >>> resp.status_code 200 >>> resp.headers Headers([('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '8339')]) >>> resp.data.splitlines()[0] '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"' ~~~ 或默认没有 response: ~~~ >>> c = Client(test_app) >>> app_iter, status, headers = c.get('/') >>> status '200 OK' >>> headers [('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '8339')] >>> ''.join(app_iter).splitlines()[0] '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"' ~~~ ### 环境搭建 0.5 新版功能. 交互测试应用 最简单的方法是使用 [EnvironBuilder](# "tests.EnvironBuilder") 类。它可以创建标准 WSGI环境和请求对象。 下面的例子创建了一个上传文件和文件表单的 WSGI 环境: ~~~ >>> from werkzeug.test import EnvironBuilder >>> from StringIO import StringIO >>> builder = EnvironBuilder(method='POST', data={'foo': 'this is some text', ... 'file': (StringIO('my file contents'), 'test.txt')}) >>> env = builder.get_environ() ~~~ 返回的环境是一个新的 WSGI 环境,可用于进一步的处理: ~~~ >>> from werkzeug.wrappers import Request >>> req = Request(env) >>> req.form['foo'] u'this is some text' >>> req.files['file'] <FileStorage: u'test.txt' ('text/plain')> >>> req.files['file'].read() 'my file contents' ~~~ 当你将一个字典传给构造函数数据, [EnvironBuilder](# "tests.EnvironBuilder") 会自动自动找出内容类型。如过你传的似乎一个字符串或者输入字符流,你不得不自己来做这些处理。 默认地它将会尝试使用 application/x-www-form-urlencoded ,如果文件被上传则只使用 multipart/form-data : ~~~ >>> builder = EnvironBuilder(method='POST', data={'foo': 'bar'}) >>> builder.content_type 'application/x-www-form-urlencoded' >>> builder.files['foo'] = StringIO('contents') >>> builder.content_type 'multipart/form-data' ~~~ 如果传入一个字符串(或一个输入流),你必须自己指定内容的类型: ~~~ >>> builder = EnvironBuilder(method='POST', data='{"json": "this is"}') >>> builder.content_type >>> builder.content_type = 'application/json' ~~~ ### 测试 API *class *tests.EnvironBuilder(*path='/'*, *base_url=None*, *query_string=None*, *method='GET'*, *input_stream=None*, *content_type=None*, *content_length=None*, *errors_stream=None*, *multithread=False*, *multiprocess=False*, *run_once=False*, *headers=None*, *data=None*, *environ_base=None*, *environ_overrides=None*, *charset='utf-8'*) 这个类为了测试可以方便的创建一个 WSGI 环境。他可以从任意数据快速创建 WSGI环境或请求对象。 这个类的签名也可用于 Werkzeug 的其他地方([create_environ()](# "tests.create_environ"), BaseResponse.from_values(), [Client.open()](# "tests.Client.open"))。因为大多数功能只可通过构造函数实现。 文件和表格数据可以被各自的 form 和 files 属性独立处理。但是以相同的参数传入构造函数:data。 data 可以是这些值: - a str: 如果一个字符串被转化为一个 [input_stream](# "tests.EnvironBuilder.input_stream"),将会设置[content_length](# "tests.EnvironBuilder.content_length") ,你还要提供一个 [content_type](# "tests.EnvironBuilder.content_type")。 - a dict: 如果是一个字典,键将是一个字符串,值是以下对象: - 一个 file-like 对象。他们会被自动转化成 FileStorage 对象。 - 一个元组。 add_file() 方法调用元组项目作为参数。 0.6 新版功能: path 和 base_url 现在是 unicode 字符串,它可以使用 iri_to_uri()函数编码。 <table class="docutils field-list" frame="void" rules="none"><col class="field-name"/><col class="field-body"/><tbody valign="top"><tr class="field-odd field"><th class="field-name">参数:</th><td class="field-body"><ul class="first last simple"><li><strong>path</strong> – 请求的路径。在 WSGI 环境它等效于 <cite>PATH_INFO</cite>。如果 <cite>query_string</cite>没有被定义,这里有一个问题要注意,<cite>path</cite> 后面的将被当作 <cite>query string</cite>。</li><li><strong>base_url</strong> – base URL 是一个用于提取 WSGI URL ,主机 (服务器名 + 服务端口)和根脚本的 (<cite>SCRIPT_NAME</cite>) 的 URL。</li><li><strong>query_string</strong> – URL 参数可选的字符串和字典。</li><li><strong>method</strong> – HTTP 方法,默认为 <cite>GET</cite>。</li><li><strong>input_stream</strong> – 一个可选输入流。不要指定它,一旦输入流被设定,你将不能更改 <a class="reference internal" href="#tests.EnvironBuilder.args" title="tests.EnvironBuilder.args"><tt class="xref py py-attr docutils literal"><span class="pre">args</span></tt></a> 属性和 <tt class="xref py py-attr docutils literal"><span class="pre">files</span></tt> 属性除非你将<a class="reference internal" href="#tests.EnvironBuilder.input_stream" title="tests.EnvironBuilder.input_stream"><tt class="xref py py-attr docutils literal"><span class="pre">input_stream</span></tt></a> 重新设为 <cite>None</cite> 。</li><li><strong>content_type</strong> – 请求的内容类型。在0.5 版本当你指定文件和表格数据的时候不必必须指定他。</li><li><strong>content_length</strong> – 请求的内容长度。当通过 <cite>data</cite> 提供数据不必必须指定他。</li><li><strong>errors_stream</strong> – 用于 <cite>wsgi.errors</cite> 可选的错误流。默认为 <tt class="xref py py-data docutils literal"><span class="pre">stderr</span></tt>。</li><li><strong>multithread</strong> – 控制 <cite>wsgi.multithread</cite>。默认为 <cite>False</cite>。</li><li><strong>multiprocess</strong> – 控制 <cite>wsgi.multiprocess</cite>。默认为 <cite>False</cite>。</li><li><strong>run_once</strong> – 控制 <cite>wsgi.run_once</cite>。默认为 <cite>False</cite>。</li><li><strong>headers</strong> – headers 一个可选的列表或者 <tt class="xref py py-class docutils literal"><span class="pre">Headers</span></tt> 对象。</li><li><strong>data</strong> – 一个字符串或者表单数据字典。看上边的 explanation。</li><li><strong>environ_base</strong> – 一个可选的默认环境。</li><li><strong>environ_overrides</strong> – 一个可选的覆盖环境。</li><li><strong>charset</strong> – 编码 unicode 数据的字符集。</li></ul></td></tr></tbody></table> path 应用的地址。(又叫 PATH_INFO) charset 编码 unicode 数据的字符集。 headers 一个带着请求 headers的 Headers 对象。 errors_stream 用于 wsgi.errors 流的错误流。 multithread wsgi.multithread 的值。 multiprocess wsgi.multiprocess 的值。 environ_base 新创建环境的基本字典。 environ_overrides 用于覆盖生成环境的带值字典。 input_stream 可选选项输入流。这个和 form / files 是相互独立的。同时如果请求方法不是 POST / PUT 或其他类似方法,不要提供输入流。 args URL 参数是 MultiDict。 base_url base URL 是一个用于提取 WSGI URL ,主机(服务器名 + 服务器端口) 和根脚本 (SCRIPT_NAME) 的 URL close() 关闭所有文件。如果把 file 对象放入 files 字典,你可以通过调用这个方法自动关闭他们。 content_length 整数的长度,反射给 [headers](# "tests.EnvironBuilder.headers")。如果你设置了 files 或 form属性不要设置这个参数。 content_type 请求的内容类型。反射给 [headers](# "tests.EnvironBuilder.headers")。如果你设置了 files 和form 属性就不能设置内容类型。 get_environ() 返回内置环境。 get_request(*cls=None*) 返回一个带数据的请求。如果没有指定请求类,将会是用 [request_class](# "tests.EnvironBuilder.request_class")。 | 参数: | **cls** – 使用 request 包装。 | |-----|-----| input_stream 一个可选的输入流。如果你设置它,将会清空 form 和 files。 query_string 查询字符串。如果你设置它, [args](# "tests.EnvironBuilder.args") 属性将不再可用。 request_class 默认的请求类 [get_request()](# "tests.EnvironBuilder.get_request")。 BaseRequest 的别名 server_name 服务器名 (只读, 使用 host 设置) server_port 整型服务器接口(只读,使用 host 设置) server_protocol* = 'HTTP/1.1'* 服务器使用协议。默认为 HTTP/1.1 wsgi_version* = (1, 0)* 使用的 WSGI 版本。默认为(1, 0)。 *class *tests.Client(*application*, *response_wrapper=None*, *use_cookies=True*, *allow_subdomain_redirects=False*) 这个类允许你发送请求给一个包裹的应用。 响应可以是一个类或者一个有三个参数工厂函数: app_iter, status and headers。默认的响应仅仅是一个元组。 例如: ~~~ class ClientResponse(BaseResponse): ... client = Client(MyApplication(), response_wrapper=ClientResponse) ~~~ use_cookies 参数默认是开启的,无论 cookies 是否被存储,他都会和请求一起传输。但是你也可以关闭 cookie。 如果你想要请求应用的子域名,你可以设置 allow_subdomain_redirects 为 True ,如果为 False ,将不允许外部重定向。 0.5 新版功能: use_cookies 是在这个版本添加的。老版本不提供内置 cookie 支持。 open(*options*) 和 [EnvironBuilder](# "tests.EnvironBuilder") 一样的参数还有一些补充: 你可以提供一个[EnvironBuilder](# "tests.EnvironBuilder") 类或一个 WSGI 环境代替 [EnvironBuilder](# "tests.EnvironBuilder")类作为参数。同时有两个可选参数 (as_tuple, buffered),可以改变返回值的类型或应用执行方法。 在 0.5 版更改: 如果为 data 参数提供一个带文件的字典,那么内容类型必须为 content_type而不是 mimetype。这个改变是为了和 werkzeug.FileWrapper 保持一致。 > follow_redirects 参数被添加到 [open()](# "tests.Client.open"). Additional parameters: <table class="docutils field-list" frame="void" rules="none"><col class="field-name"/><col class="field-body"/><tbody valign="top"><tr class="field-odd field"><th class="field-name">参数:</th><td class="field-body"><ul class="first last simple"><li><strong>as_tuple</strong> – 在表格中返回一个元组 <tt class="docutils literal"><span class="pre">(environ,</span> <span class="pre">result)</span></tt>。</li><li><strong>buffered</strong> – 把这个设为 True 来缓冲区运行应用。这个将会为你自动关闭所有应用。</li><li><strong>follow_redirects</strong> – 如果接下来 <cite>Client</cite> HTTP 重定向,这个将会设为 True。</li></ul></td></tr></tbody></table> get(*options*) 和 open 相似,但是方法强制执行 GET。 post(*options*) 和 open 相似,但是方法强制执行 POST。 put(*options*) 和 open 相似,但是方法强制执行 PUT。 delete(*options*) 和 open 相似,但是方法强制执行 DELETE。 head(*options*) 和 open 相似,但是方法强制执行 HEAD。 tests.create_environ([*options*]) 根据传入的值创建一个 WSGI 环境。第一个参数应该是请求的路径,默认为 ‘/'。另一个参数或者是一个绝对路径(在这个例子中主机是 localhost:80)或请求的完整路径,端口和脚本路径。 它和 [EnvironBuilder](# "tests.EnvironBuilder") 构造函数接受相同的参数。 在 0.5 版更改: 这个函数现在是一个 [EnvironBuilder](# "tests.EnvironBuilder") 包裹,在 0.5 版本被添加。需要 headers, environ_base, environ_overrides 和 charset 参数。 tests.run_wsgi_app(*app*, *environ*, *buffered=False*) 返回一个应用输出的元组形式 (app_iter, status, headers)。如果你通过应用返回一个迭代器他将会工作的更好。 有时应用可以使用 start_ewsponse 返回的 write() 回调函数。这将会自动解决边界情况。如果没有得到预期输出,你应该将 buffered 设为 True 执行buffering 如果传入一个错误的应用,这个函数将会是未定义的。不要给这个函数传入一个不标准的 WSGI 应用。 <table class="docutils field-list" frame="void" rules="none"><col class="field-name"/><col class="field-body"/><tbody valign="top"><tr class="field-odd field"><th class="field-name">参数:</th><td class="field-body"><ul class="first simple"><li><strong>app</strong> – 要执行的应用。</li><li><strong>buffered</strong> – 设为 <cite>True</cite> 来执行 buffering.</li></ul></td></tr><tr class="field-even field"><th class="field-name">返回:</th><td class="field-body"><p class="first last">元组形式 <tt class="docutils literal"><span class="pre">(app_iter,</span> <span class="pre">status,</span> <span class="pre">headers)</span></tt></p></td></tr></tbody></table>
';