A. python django 做了个web ,在登录界面我想直接调用系统的login模板,可是每次登录成功之后就跳到
系统的login.html里包含一个重定向URL的next隐藏域。有这么一行:
<input type="hidden" name="next" value="{{ next }}" />
登陆以后跳转到系统默认的/accounts/profile
你把value改成你想要跳转的url或者给next重新传一个url也行
B. 如何用Python写一个http post请求
你运气真好,我这刚好有现成的,下面大写的常量就是一些字符串,涉及我们自己的协议,就不发你了,你随便写个就行
defRequestCenter(data,url,web="127.0.0.1",port=9228):
headDic={}
headDic[REQUEST_HEAD_LENGTH]=len(data)
tempList=[]
tempList.append(headDic)
tempList.extend(data)
#远程访问
count=0
jsonData=json.mps(tempList)
headers={"Content-type":"application/json"}
state=-1
whilecount<1:
com=httplib.HTTPConnection(web,port,True)
com.request("POST",url,jsonData,headers)
response=com.getresponse()
time.sleep(0.5)
infoList=[]
state=response.status
if200<=state<300:
infoList=json.loads(response.read())
com.close()
break
else:
count+=1
com.close()
returninfoList
C. python多线程并发访问多个URi
我想问问看你说的”访问一个站点“是什么意思,是下载一个文件吗?还是需要submit一些表单上去还是其他什么访问法?还有多线程是用来干什么的?是多个线程同时下载一个文件让这个文件可以下载得更快吗?还是其他什么目的?
本身python访问web就很简单,urllib的几个函数一调用就好了,不过不清楚你想要做什么,所以我感觉不知道怎么回答你。
D. 如何用Python写一个web框架
STEP.1
我们首先得选择基于什么协议来写这种框架。我们可以选择CGI协议,或者是WSGI接口。如果使用CGI,实际上我们只是按着CGI的规范写了一个python程序,然后每次服务器收到请求,就fork一个程序来执行它,然后返回一个http文档,性能比较低下。对于WSGI,而是一个存在于服务器和应用间的接口,在WSGI之前,web应用都是依赖于服务器的,现在流行的python框架都支持WSGI接口。
STEP.2 PEP-333
这一段是PEP-333 所提供的样例代码。
def simple_app(environ, start_response):
"""Simplest possible application object"""
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['Hello world!
']
这里的application被传入了两个值。
environ
start_response。
environ是一个字典,保存了http请求的信息。
start_response是一个函数,发送http响应。她有两个参数status 和 start_headers。
status必须是由状态编号和具体信息组成的字符串,必须符合RFC 2616。
start_headers是一个(header_name,header_value) 元组的列表元组列表。其中的hearder_name必须是合法的http header字段名。在RFC 2616, Section 4.2中有详细定义。
当然官方还给出了类的实现。
了解了如上信息后,基本上可以开始了。我们就到官方给的代码上进行修改吧。
STEP.3 将路径链接到函数
首先我们得把用户请求的路径,链接到函数。我们可以实现一个getPage方法,专门做这件事。我们所拥有的信息,只有environ['PATH_INFO']。
写到这里之后,每次添加页面,就只需要在urls列表中添加一个元祖就行了。
STEP.4 获取模版
既然是写web app,模版肯定是得有的。这里我提供了一种getTemplate方法来做这件事。不过我只提供了变量的替换。
STEP.5 POST数据的处理
要想获取POST数据,我们得通过environ['wsgi.input']来处理。而他实际上就是系统的标准输入。
知道这点后就很好写了。
数据库的链接
STEP.6 清理工作
很多配置如果放到代码中,会增加阅读负担。于是把urls,model抽取出来。
使得配置更加方便。
E. python的web服务代码怎么写要求能读取请求头和定义返回头的值 (不够可以加分)
server端口: 8888端口
server根目录: "../http/"
如下代码是一个简单的例子,并没有限制对其他目录的访问:
#!/usr/bin/env python
import BaseHTTPServer
import os
httpPort = 8888
documentRoot = os.curdir + "../http/"
class exampleHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
try:
print self.server
print self.path
print self.client_address
print self.command
print self.request_version
print self.headers
if self.path.endswith(".html") or self.path.endswith(".htm"):
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.end_headers()
f = open(documentRoot + self.path)
self.wfile.write(f.read())
f.close()
else:
self.send_error(404, "%s was not supported" % self.path)
except IOError:
self.send_error(404, "%s was not found" % self.path)
def run(server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler):
server_address = ('', httpPort)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
if __name__ == '__main__':
run(handler_class = exampleHandler)
F. 如何利用cURL和python对服务端和web端进行接口测试
工具描述
cURL是利用URL语法在命令行方式下工作的文件传输工具,是开源爱好者编写维护的免费工具,支持包括Windows、linux、Mac等数十个操作系统,最新版本为7.27.0,但是我推荐大家使用7.26.0,从这里可以下载7.26.0版本。
以下是官方介绍的翻译: cURL是一个使用URL语法来传输数据的命令行工具,支持DICT,FILE,FTP,FTPS,GOPHER,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,POP3,POP3S,RTMP,RTSP,SCP,SFTP,SMTP,SMTPS,Telnet和TFTP。 cURL支持SSL证书,HTTP POST,HTTP PUT,FTP上传,HTTP基础表单上传,代理,cookies,用户+密码身份验证(Basic, Digest, NTLM, Negotiate, kerberos...),恢复文件传输,隧道代理等等。
Python是一种面向对象、直译式计算机程序设计语言,由Guido van Rossum于1989年底发明,它的强大和易用就无需多做说明了,在web开发中或者对开发速度要求较高的开发中应用十分广,不过因为属于脚本类语言,它的性能始终比不上C++、C等语言。
本文主要利用实例说明这两款工具的在测试中的部分用途,更多用法留待大家继续探索。
应用场景
使用cURL模拟客户端对服务端进行查询
在进行接口测试时,应该先找开发人员提供接口列表和对应参数,这样测试的时候就可以验证测试方法是否正确,不过如果可以用浏览器模拟操作的话,也可以自己先试试的,后面的例子会提到。
首先使用客户端访问需要测试的服务端接口,用wireshark抓包结果如下:
把查询字符串以multipart方式post数据到服务器的file_health_info.php接口。
Tips:
Windows版的cURL不像Linux或者Mac一样属于系统自带工具,需要下载,如果要在命令提示符下使用就需要跳转到工具所在目录下才能运行,十分麻烦,我们可以直接把这个工具文件放到Windows目录下,这样无论在哪个目录都可以直接使用“curl”命令运行工具了。
cURL默认就是以post方式发送数据的,所以只需要加入multipart方式就可以了,-F在cURL帮助中的解释是:
-F, --form CONTENT Specify HTTP multipart POST data (H)
--form-string STRING Specify HTTP multipart POST data (H)
--ftp-account DATA Account data string (F)
--ftp-alternative-to-user COMMAND String to replace "USER [name]" (F)
--ftp-create-dirs Create the remote dirs if not present (F)
--ftp-method [MULTICWD/NOCWD/SINGLECWD] Control CWD usage (F)
--ftp-pasv Use PASV/EPSV instead of PORT (F)
Specify HTTP multipart POST data正好满足我们的要求,所以模拟的语句是:
curl -F "newmd5=###25016566###d:\test.exe###1###" file_health_info.php
后面的都是参数,测试前就要找开发确认好。
不过因为服务端支持以gzip方式返回数据,所以我们还可以在请求中加入—compressed参数,即是:
curl --compressed -F "newmd5=###25016566###d:\test.exe###1###"file_health_info.php
为了更好判断服务端接口是否正常,除了对返回数据进行判断外,我们还需要对服务端返回的数据包头进行解析,所以还可以在cURL请求中加入-i参数,最终这个测试语句就变为:
curl –i --compressed -F "newmd5=###25016566###d:\test.exe###1###"file_health_info.php
模拟完成后就要考虑判断返回值的事了,我们首先在命令提示符下运行这个语句,看看返回值。
运行以上命令后,返回的数据如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Date: Fri, 24 Aug 2012 07:47:45 GMT
Content-Type: application/xml
Transfer-Encoding: chunked
Connection: keep-alive
Server: 360 web server
Content-Encoding: gzip
<?xml version="1.0" encoding="GBK" ?>
<ret>
<retinfo code="0" msg="Operation success" total="1" success="1" empty="0"
cost="999.92752075195"/>
<softs>
<soft>
<md5></md5>
<sha1></sha1>
<level>4040</level>
<e_level>40.3</e_level>
<size></size>
<soft_name><![CDATA[]]> </soft_name>
<describ><![CDATA[]]></describ>
<file_desc><![CDATA[]]></file_desc>
<upload>0</upload>
<attr_upload>2</attr_upload>
<class><![CDATA[private]]></class>
<malware><![CDATA[cloud.virus]]></malware>
<is_sys_file>0</is_sys_file>
<is_rep>0</is_rep>
<age>0</age>
<pop>0</pop>
</soft>
</softs>
</ret>
数据包包头是常见的,一般来说,我们只要判断包头中含有“HTTP/1.1 200 OK”就可以确定服务端正常返回了数据。另外从内容可以看到这是一个xml格式的数据包,我们只需要判断是否存在关键的字段即可,比如<level>,确定这些之后我们就可以在python中添加如下案例代码了:
首先运行指定的curl命令:
response = os.popen('''curl -i --compressed -F "newmd5=###25016566###d:\test.exe###1###"
然后判断返回值中是否存在我们想要的字段:
self.assertNotEqual(response.find('HTTP/1.1 200 OK'),-1)
self.assertNotEqual(response.find('<level>'),-1)
上面的内容看起来差不多可以了,但实际还不够严谨,因为服务端返回的这些数据是从数据库中获取的,所以我们还需要查询数据库获取指定值,判断是否和数据包中的一致,比如<level>:
首先使用python登录数据库服务器:
conn = MySQLdb.connect(host='172.22.54.31', user='user',passwd='test321',db='cloud')
cursor = conn.cursor()
count = cursor.execute('SELECT plevel FROM file where md5=""')
result = cursor.fetchone()
然后判断返回值中的level是否数据库中的值:
self.assertNotEqual(response.find('''<level>%s</level>'''%result[0]),-1)
测试时除了使用cURL等工具进行模拟,还可以自己用python或其他语言写代码进行post数据,不过当时简单起见所以就选择了用cURL测试。
使用cURL模拟控制台登录
说到模拟登录或者模拟点击,很多同学可能直接联想到QTP等模拟界面操作的工具,事实上这种工具有一个很大的弊端是太依赖控件,如果界面控件变了,那么可能整个脚本就无效了,现在的程序设计都倾向界面逻辑分离,这样修改界面时就不会动到底下的功能接口,开发人员可以随时修改界面控件,如果还是采取QTP等模拟点击的方法测试,结果可能是事倍功半的,如果测试时直接点用接口就可以避免这种问题。
下面的例子是模拟控制台登录的,登录URL为:
index.php?r=site/login ,首先使用浏览器登录一次,看看实际效果如何。
Tips:
测试php或其他web程序时建议使用chrome,因为它自带的Developer Tools十分好用,当然firefox或者IE9也有类似的工具,看个人习惯吧。按F12打开工具,选择Network标签页,然后输入用户名、密码点击登录,这时Network下方会显示登录过程中浏览器想控制台请求的所有数据,包括请求类型、表单数据等,这些是我们模拟操作的数据来源。
从上图可以获取几个重点信息:请求URL、请求类型、数据类型、数据内容、并且支持gzip压缩等。我们用curl模拟如下:
curl -i --compressed cloud/index.php?r=site/login -d “username=admin” -d “userpass=admin”
使用-i和—compressed的原因再上一个例子已经说了,这里不再赘述,重点是后面的-d,它在官方帮助的解释是:
-d, --data DATA HTTP POST data (H)
--data-ascii DATA HTTP POST ASCII data (H)
--data-binary DATA HTTP POST binary data (H)
--data-urlencode DATA HTTP POST data url encoded (H)
--delegation STRING GSS-API delegation permission
--digest Use HTTP Digest Authentication (H)
--disable-eprt Inhibit using EPRT or LPRT (F)
--disable-epsv Inhibit using EPSV (F)
而我们从Developer Tools返回的数据已经知道,返回数据的格式是
“application/x-www-form-urlencoded”,所以很明显需要使用-d的HTTP POST data url encoded特性。不过格式中还有关键字form,莫非也支持-F参数登录,试试:
curl -i --compressed cloud/index.php?r=site/login -F “username=admin” -F “userpass=admin”,果然成功,呵呵~
也许有同学有疑问,为何不模拟warnsetup、refer,这是因为测试时发现登录界面只需要用户名和密码就够了,refer 用于记录来源网页,在这里用处不大,warnsetup只是用于验证登录码的,这个已经去掉了。
接下来要验证数据,我们在命令提示符中运行上面的命令,返回结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 302 Moved Temporarily
Date: Fri, 24 Aug 2012 08:29:07 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.3
Set-Cookie: PHPSESSID=; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=; path=/
Location: ./index.php
Server: 360 web server
很奇怪吧,乍一看控制台没有返回任何有用信息,不过里面那句HTTP/1.1 302 Moved Temporarily是不是特别眼熟?这个特殊的302(表示http重定向)正是我们在Developer Tools看到的状态值,看到这个已经可以80%确定我们登录已经成功了,更重要的是返回包中的内容:Location: ./index.php,这说明控制台已经通知请求端跳转到index.php,如果登录失败控制台会继续停留在当前登录界面的,我们只需要修改curl语句中的用户名或者密码就知道了,这种情况下返回包就是登录界面的php源码,这里不再赘述。
使用cURL以get方式测试控制台搜索接口
测试方法同上面差不多,首先使用chrome打开控制台进入对应页面,在搜索框中输入“test.exe”,点击搜索,使用developer tools抓包,内容如下:
cURL模拟get方式发送数据的参数是-G,了解这个后面要模拟就很简单了:
curl -i --compressed -G “cloud/index.php?r=file_cloud/api/search&filename=&bg=0&lm=19 ”
其中每个参数的含义要分别了解:filename表示输入的关键字,bg表示数据库第一行,lm表示共显示19行数据。这个接口返回的数据如下:
{"rows":[{"level":"10","plevel":"10","id":"20","md5":"","soft_name":"","soft_desc":"","file_desc":"","is_sys_file":"127","size":"41984","is_rep":"0","file_name":"apihex86.d
ll","file_version":"6.1.7600.16385","proct_version":"6.1.7600.16385","right":"\u00a9 Microsoft Corporation. All rights reserved.","lang":"0","org_name":"YXBpaGV4ODYuZGxs","sign_name":"TWljcm9zb2Z0IFdpbmRvd3M=","company_name":"Microsof
t Corporation","update_time":"2012-07-31 18:14:27","create_time":"2012-07-31 18:14:27","creator_mid":""}],"count":"1"}
分别是文件属性和文件信息,这涉及到两个数据库表,所以验证数据需要用python从两张表中获取对应信息。
从第一张表获取文件属性,比如只获取plevel:
SELECT plevel FROM `file` where md5=""
从第二张表获取文件信息,比如只获取company_name:
SELECT company_name FROM file_info where md5=""
Python代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
conn = MySQLdb.connect(host='%s'% self.host, user='user',passwd='test321',db='cloud')
cursor = conn.cursor()
count = cursor.execute('SELECT plevel FROM `file` where md5=""')
result = cursor.fetchone()
self.assertNotEqual(response.find(str(result[0])),-1)
count = cursor.execute('SELECT company_name FROM file_info where md5=""')
result1 = cursor.fetchone()
self.assertNotEqual(response.find(result1[0]),-1)
当然严谨的测试案例是每一个属性字段都需要进行查找和匹配,这里就不再赘述了。
后记:这种接口测试用到的无非就是curl、python的unitest而已,可能有的人会疑问,为什么用curl而不用py自带的pycurl或者request之类,我觉得只要能满足需求,能够用现成的就用现成的,怎么简单怎么来。搞一堆代码维护起来也麻烦啊,现在qa行业跳槽也比较频繁,万一换了个人看不懂你的代码怎么办?呵呵
G. 如何开发一个Python web框架
首先你需要知道一个Web应用基本的请求处理流程。以最简单最原始的动态网页为例,你点击链接(GET),提交表单(POST),就是与服务器端建立了连接之后发送了一个HTTP请求(RFC2616 5.1节,之后都以HTTP 1.1为例),里面至少有方法(动词,就是GET啦POST什么的,详见RFC2616第9节),地址(URL),HTTP版本,还可能带上Cookie(会话的一般实现机制),缓存相关的信息(RFC2616 13节),User-Agent串等等一堆信息。对于POST请求我们还有表单内容作为请求实体(RFC2616 7.2节),里面是你填写的表单内容。
于是我们有了一些关于请求的数据,不过现在一般来讲这些数据还在前端服务器(反向代理,比如nginx,暂且忽略掉负载均衡,反正是透明的,也不考虑裸WSGI容器直接扛请求的情况)的手上,还没有传进后端语言(这里是Python)。我们就针对每一种语言都有特定的机制,用来将HTTP的请求信息映射到相应的编程语言范畴,叫做Web服务器界面(Web server interface),通用如CGI/FCGI/SCGI,特定于某一语言如WSGI/PSGI/Rack/...,特定于某一操作系统如ISAPI(这货还活着?),一些已经不再使用的就不提了。总之在Python世界里这就是WSGI(PEP 3333, Web Server Gateway Interface),它就定义了Python语言与Web服务器之间的界面。在WSGI里,
请求的处理过程被映射为对应用callable的调用(application(environ, start_response),知乎不支持inline代码块?);
请求信息被映射到environ字典中的相应键值,比如请求方法被映射到environ['REQUEST_METHOD'],请求的“相对路径”被映射到environ['PATH_INFO'](过度简化;暂且不提WSGI应用挂载点,框架层一般也不用关心这个,挂载WSGI应用一般是WSGI容器如gunicorn、uWSGI之类组件的工作);
发送响应头的动作被映射到调用start_response(status, response_headers)(不考虑可选的第三个参数异常信息);
返回响应数据被映射到application返回iterable的动作。
于是响应便从Python返回到Web服务器,再被发送回浏览器,浏览器将响应内容渲染,一个请求就完成啦。
有了这样的感性认识,那么我们作为Python Web开发框架的作者,要做的事情就是在WSGI规范的基础之上,提供尽可能便捷的开发手段和尽可能低的框架开销,也即我们的代码将要工作在WSGI与业务逻辑的中间层。架构上,Web开发框架或多或少都遵循MVC的设计模式(Django管它叫MTV,其实差不多)。同时,由于框架位于中间件的位置,加上其鼓励模块化与代码复用的性质,自然需要为常见的HTTP操作提供抽象。这里就可以展开一些话题:
请求路径到view/controller的映射,请求参数的解析(routing,也叫路由)。
正则匹配的方案,比如Django内置了一个简单的正则表达式解析组件,能解析一般常见语法的正则表达式,把capturing groups解析成位置参数,named capturing groups解析成关键字参数。
也有DSL的方案,比如Werkzeug的路由组件。
请求实体的处理。表单解析,配合Web服务器进行上传文件处理。
正常的urlencoded表单,JSON表单,text/plain数据,multi-part表单
multi-part附件,附件操作API
大文件上传(这个一般会被前端服务器保存在磁盘上的临时文件里,比方说nginx就是这么实现的)。
会话。HTTP是无状态(stateless)的,这个特点非常重要。如果没有会话,你连续做几个请求,却没有手段证明你们是同一个人/同一台机器(你完全可能是代理服务器)。
存储会话数据的会话后端(内存数据结构?文件?RDBMS?Redis?Memcache?)
安全机制(HMAC什么的,可以参考beaker的secure cookie实现)
请求处理流程中的会话中间件(从Cookie中提取会话,从query string中提取会话,从自定义头中提取会话,等等)
View/Controller界面。发挥你的创造力,用上你的工程经验。
Function-based or Class-based views? 参考:Django, Bottle, web.py, Tornado等一票框架的做法
框架的可选机制与服务如何暴露,
装饰器?(比如@login_required 这种额外要求)
回调?(能想到的只有Tornado和Twisted这种异步框架做事情的方式,还有整个JS生态系统都是回调(不考虑Promise什么的)的思路)
传入应用(业务逻辑)层的数据结构如何设计?(HttpRequest等价物,名字可能记不清了)
响应数据结构如何设计?(HttpResponse等价物,同上)
数据库操作封装。Web应用基本都是数据为中心,这个组件非常有必要,也是撰写可复用代码必须的一环,毕竟光是框架抽象了,数据库操作还是裸SQL什么的,到时候生产环境一换(比如MySQL变pgsql)还不是傻眼。
关系型数据库。一站式解决方案参考:Django ORM、SQLAlchemy;轻量级解决方案参考各数据库Python绑定。
非关系数据库。各数据库Python绑定(pymongo, riak, redis-py之类),这个没什么可替代方案了,因为本来各种NoSQL库都是适应某一特殊需求设计的,没什么互相替换的必要,那意味着重新进行技术选型。
H. 如何用python 来mock一个web响应
什么是mock?
mock在翻译过来有模拟的意思。这里要介绍的mock是辅助单元测试的一个模块。它允许您用模拟对象替换您的系统的部分,并对它们已使用的方式进行断言。
在Python2.x 中 mock是一个单独模块,需要单独安装。
> pip install -U mock
在Python3.x中,mock已经被集成到了unittest单元测试框架中,所以,可以直接使用。
可能你和我初次接触这个概念的时候会有这样的疑问:把要测的东西都模拟掉了还测试什么呢?
但在,实际生产中的项目是非常复杂的,对其进行单元测试的时候,会遇到以下问题:
接口的依赖
外部接口调用
测试环境非常复杂
单元测试应该只针对当前单元进行测试, 所有的内部或外部的依赖应该是稳定的, 已经在别处进行测试过的.使用mock 就可以对外部依赖组件实现进行模拟并且替换掉, 从而使得单元测试将焦点只放在当前的单元功能。
简单的例子
我们先从最简单例子开始。
molar.py
#molar.py
class Count():
def add(self):
pass
这里要实现一个Count计算类,add() 方法要实现两数相加。但,这个功能我还没有完成。这时就可以借助mock对其进行测试。
mock_demo01.py
from unittest import mock
import unittest
from molar import Count
# test Count class
class TestCount(unittest.TestCase):
def test_add(self):
count = Count()
count.add = mock.Mock(return_value=13)
result = count.add(8,5)
self.assertEqual(result,13)
if __name__ == '__main__':
unittest.main()
count = Count()
首先,调用被测试类Count() 。
count.add = mock.Mock(return_value=7)
通过Mock类模拟被调用的方法add()方法,return_value 定义add()方法的返回值。
result = count.add(2,5)
接下来,相当于在正常的调用add()方法,传两个参数2和5,然后会得到相加的结果7。然后,7的结果是我们在上一步就预先设定好的。
self.assertEqual(result,7)
最后,通过assertEqual()方法断言,返回的结果是否是预期的结果7。
运行测试结果:
> python3 mock_demo01.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
这样一个用例就在mock的帮助下编写完成,并且测试通过了。
完成功能测试
再接下来完成mole.py文件中add()方法。
#mole.py
class Count():
def add(self, a, b):
return a + b
然后,修改测试用例:
from unittest import mock
import unittest
from mole import Count
class MockDemo(unittest.TestCase):
def test_add(self):
count = Count()
count.add = mock.Mock(return_value=13, side_effect=count.add)
result = count.add(8, 8)
print(result)
count.add.assert_called_with(8, 8)
self.assertEqual(result, 16)
if __name__ == '__main__':
unittest.main()
count.add = mock.Mock(return_value=13, side_effect=count.add)
side_effect参数和return_value是相反的。它给mock分配了可替换的结果,覆盖了return_value。简单的说,一个模拟工厂调用将返回side_effect值,而不是return_value。
所以,设置side_effect参数为Count类add()方法,那么return_value的作用失效。
result = count.add(8, 8)
print(result)
这次将会真正的调用add()方法,得到的返回值为16(8+8)。通过print打印结果。
assert_called_with(8,8)
检查mock方法是否获得了正确的参数。
解决测试依赖
前面的例子,只为了让大家对mock有个初步的印象。再接来,我们看看如何mock方法的依赖。
例如,我们要测试A模块,然后A模块依赖于B模块的调用。但是,由于B模块的改变,导致了A模块返回结果的改变,从而使A模块的测试用例失败。其实,对于A模块,以及A模块的用例来说,并没有变化,不应该失败才对。
这个时候就是mock发挥作用的时候了。通过mock模拟掉影响A模块的部分(B模块)。至于mock掉的部分(B模块)应该由其它用例来测试。
# function.py
def add_and_multiply(x, y):
addition = x + y
multiple = multiply(x, y)
return (addition, multiple)
def multiply(x, y):
return x * y
然后,针对 add_and_multiply()函数编写测试用例。func_test.py
import unittest
import function
class MyTestCase(unittest.TestCase):
def test_add_and_multiply(self):
x = 3
y = 5
addition, multiple = function.add_and_multiply(x, y)
self.assertEqual(8, addition)
self.assertEqual(15, multiple)
if __name__ == "__main__":
unittest.main()
运行结果:
> python3 func_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
目前运行一切正确常,然而,add_and_multiply()函数依赖了multiply()函数的返回值。如果这个时候修改multiply()函数的代码。
……
def multiply(x, y):
return x * y + 3
这个时候,multiply()函数返回的结果变成了x*y加3。
再次运行测试:
> python3 func_test.py
F
======================================================================
FAIL: test_add_and_multiply (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "fun_test.py", line 19, in test_add_and_multiply
self.assertEqual(15, multiple)
AssertionError: 15 != 18
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
测试用例运行失败了,然而,add_and_multiply()函数以及它的测试用例并没有做任何修改,罪魁祸首是multiply()函数引起的,我们应该把 multiply()函数mock掉。
import unittest
from unittest.mock import patch
import function
class MyTestCase(unittest.TestCase):
@patch("function.multiply")
def test_add_and_multiply2(self, mock_multiply):
x = 3
y = 5
mock_multiply.return_value = 15
addition, multiple = function.add_and_multiply(x, y)
mock_multiply.assert_called_once_with(3, 5)
self.assertEqual(8, addition)
self.assertEqual(15, multiple)
if __name__ == "__main__":
unittest.main()
@patch("function.multiply")
patch()装饰/上下文管理器可以很容易地模拟类或对象在模块测试。在测试过程中,您指定的对象将被替换为一个模拟(或其他对象),并在测试结束时还原。
这里模拟function.py文件中multiply()函数。
def test_add_and_multiply2(self, mock_multiply):
在定义测试用例中,将mock的multiply()函数(对象)重命名为 mock_multiply对象。
mock_multiply.return_value = 15
设定mock_multiply对象的返回值为固定的15。
ock_multiply.assert_called_once_with(3, 5)
检查ock_multiply方法的参数是否正确。
再次,运行测试用例,通过!
---------------------------------------------------
I. 安装好Python后,怎么在浏览器输出,就像PHP安装好环境后输出localhost一样可以在浏览器显示效果
Python可以作为web开发语言来进行使用,但是它不是专门用来做web开发来使用的,所以你无法直接安装以后就能在浏览器当中输出。当然既然可以用来做web语言开发,也就是或它在进行一定配置以后可以在浏览器当中进行输出。
我们先编写hello.py,实现Web应用程序的WSGI处理函数:
#hello.py
defapplication(environ,start_response):
start_response('200OK',[('Content-Type','text/html')])
return'<h1>Hello,web!</h1>'
然后,再编写一个server.py,负责启动WSGI服务器,加载application()函数:
#server.py
#从wsgiref模块导入:
fromwsgiref.simple_serverimportmake_server
#导入我们自己编写的application函数:
fromhelloimportapplication
#创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd=make_server('',8000,application)
print"ServingHTTPonport8000..."
#开始监听HTTP请求:
httpd.serve_forever()
确保以上两个文件在同一个目录下,然后在命令行输入python server.py来启动WSGI服务器
启动成功后,打开浏览器,输入http://localhost:8000/,就可以看到结果了:
J. python怎么实现web页面敲入linux命令,传入到另一个服务器执行
这个不难,我说下原理,具体你自己实现。浏览器向web服务器提交要执行的linux命令,服务端调用os.system等系统交互的方法,去执行所提交的命令,然后获取执行后标准输出、标准错误,将这些标准输出、错误以response返回给浏览器。