测试.docx
《测试.docx》由会员分享,可在线阅读,更多相关《测试.docx(16页珍藏版)》请在冰点文库上搜索。
![测试.docx](https://file1.bingdoc.com/fileroot1/2023-6/20/53be2d37-5d64-43aa-9350-6ad14290d17f/53be2d37-5d64-43aa-9350-6ad14290d17f1.gif)
测试
1)doctest
使用doctest是一种类似于命令行尝试的方式,用法很简单,如下
复制代码代码如下:
deff(n):
"""
>>>f
(1)
1
>>>f
(2)
2
"""
print(n)
if__name__=='__main__':
importdoctest
doctest.testmod()
应该来说是足够简单了,另外还有一种方式doctest.testfile(filename),就是把命令行的方式放在文件里进行测试。
2)unittest
unittest历史悠久,最早可以追溯到上世纪七八十年代了,C++,Java里也都有类似的实现,Python里的实现很简单。
unittest在python里主要的实现方式是TestCase,TestSuite。
用法还是例子起步。
复制代码代码如下:
fromwidgetimportWidget
importunittest
#执行测试的类
classWidgetTestCase(unittest.TestCase):
defsetUp(self):
self.widget=Widget()
deftearDown(self):
self.widget.dispose()
self.widget=None
deftestSize(self):
self.assertEqual(self.widget.getSize(),(40,40))
deftestResize(self):
self.widget.resize(100,100)
self.assertEqual(self.widget.getSize(),(100,100))
#测试
if__name__=="__main__":
#构造测试集
suite=unittest.TestSuite()
suite.addTest(WidgetTestCase("testSize"))
suite.addTest(WidgetTestCase("testResize"))
#执行测试
runner=unittest.TextTestRunner()
runner.run(suite)
简单的说,1>构造TestCase(测试用例),其中的setup和teardown负责预处理和善后工作。
2>构造测试集,添加用例3>执行测试需要说明的是测试方法,在Python中有N多测试函数,主要的有:
TestCase.assert_(expr[,msg])
TestCase.failUnless(expr[,msg])
TestCase.assertTrue(expr[,msg])
TestCase.assertEqual(first,second[,msg])
TestCase.failUnlessEqual(first,second[,msg])
TestCase.assertNotEqual(first,second[,msg])
TestCase.failIfEqual(first,second[,msg])
TestCase.assertAlmostEqual(first,second[,places[,msg]])
TestCase.failUnlessAlmostEqual(first,second[,places[,msg]])
TestCase.assertNotAlmostEqual(first,second[,places[,msg]])
TestCase.failIfAlmostEqual(first,second[,places[,msg]])
TestCase.assertRaises(exception,callable,...)
TestCase.failUnlessRaises(exception,callable,...)
TestCase.failIf(expr[,msg])
TestCase.assertFalse(expr[,msg])
TestCase.fail([msg])
最近公司进行了Python项目测试的工作,这将意味着Python测试可以编写得更简洁、更统一,能够产生更好的结果报告。
对于一般新入手的开发人员,如果只想在Python项目测试或添加新特性之前检查包是否能够在他自己的平台上进行工作,那么test_suite入口点是非常方便的,这也避免程序员多走的弯路。
本文讨论先进的测试框架如何提供健壮的应用程序测试自动发现,以及这如何替代过去维护的集中式测试列表。
Python编程社区非常重视单元测试和功能性测试。
这种风气不但有助于确保组件和应用程序最初的质量,还促使程序员不断调整和改进代码。
本文是讨论现代Python测试框架的三篇系列文章的第二篇。
本系列中的第一篇文章介绍了zope.testing、py.test和nose,介绍它们如何影响Python项目编写和维护测试的方式。
本文介绍如何调用这三种框架、它们如何在项目中发现测试以及如何选择并运行测试。
最后一篇文章将讨论如何通过各种报告特性让测试支持更强大的技术。
Python测试的黑暗时代Python项目测试曾经是非常特殊化、个人化的活动。
开发人员可能先在单独的Python脚本中编写每组测试。
然后,编写一个名为test_all.py或tests.py的脚本,这个脚本导入并运行他的所有测试。
但是,无论这个过程的自动化做得多么好,这种方式仍然是特殊化的:
参与项目的每个开发人员都必须知道测试脚本放在哪里以及如何调用它们。
如果某个Python开发人员从事十几个项目,他就必须记住十几个测试命令。
test_all.py(或项目采用的其他名称)还可能手工导入所有其他测试,这可能导致风险。
如果这个集中的测试列表过时了(常常是由于开发人员添加了新的测试套件。
手工运行它,但是忘了把它添加到中心脚本中),那么在Python包投入生产之前的最后一次测试就会遗漏许多测试。
这种无政府状态的另一个缺点是,它要求每个测试文件包含样板代码,从而能够作为单独的命令运行。
如果查看Python项目测试或当今的一些Python项目,会看到许多这样的测试示例:
1.# test_old.py - The old way of doing things
2.
3.import unittest
4.
5.class TruthTest(unittest.TestCase):
6. def testTrue(self):
7. assert True == 1
8.
9. def testFalse(self):
10. assert False == 0
11.
12.if __name__ == '__main__':
13.unittest.main()
本系列的第一篇文章已经讨论过基于TestCase类的测试在现代环境中为什么常常是不必要的。
但是,现在注意最后两行:
它们起什么作用?
答案是,它们检测什么时候从命令行单独运行这个test_old.py脚本。
在这种情况下,它们运行一个unittest简便函数,这个函数在模块中搜索测试并运行它们。
它们使这个测试文件可以独立于项目范围的测试脚本单独运行。
显然,在数十甚至数百个测试模块中复制相同的代码非常麻烦。
另一个不太明显的缺点是这种做法不利于标准化。
如果test_main()函数不够完善,无法检测出某个模块的测试,那么这个模块的行为可能与其他测试套件不匹配。
因此,每个模块在测试类的名称、操作方式和运行方式方面稍有差异。
由于主流Python测试框架的出现,上述的所有问题已经解决了,而且每种框架解决这些问题的方式大致相同。
首先,这三种测试框架都提供了从操作系统命令行运行测试的标准方法。
这样,每个Python项目测试就不再需要在代码基中维护全局测试脚本。
zope.testing包运行测试的机制是最特殊化的:
因为Zope开发人员常常使用buildout设置他们的项目,常常通过buildout.cfg文件中的zc.recipe.testrunnerrecipe安装测试脚本。
但是,结果在不同的项目上相当一致:
在我遇到的每个Zope项目中,开发buildout都会创建一个./bin/test脚本,可以通过它调用项目的测试。
py.test和nose项目的做法更意思。
它们都提供一个命令行工具,所以每个项目完全不需要有自己的测试命令:
14.# Run "py.test" on the project
15.# in the current directory...
16.
17.$ py.test
18.
19.# Run "nose" on the project
20.# in the current directory...
21.
22.$ nosetests
py.test和nosetests工具甚至有几个相同的命令行选项,比如-v选项在执行测试时输出测试的名称。
可能过不了多久,只要程序员熟悉这两种工具,就能够运行大多数公共Python包的测试
可爱的Python:
Python中的测试框架
确保软件如您所愿地工作
DavidMertz,Ph.D.(mertz@gnosis.cx),开发人员,GnosisSoftware,Inc
DavidMertz感觉脾气有些暴躁。
可以通过mertz@gnosis.cx与David联系,也可以通过他的个人网页了解他的生活。
请阅读他的TextProcessinginPython一书。
欢迎提出关于过去或将来专栏的意见和建议。
简介:
在这一期文章中,David研究了Python的两个用于单元测试的标准模块:
unittest和doctest。
这些模块扩展了用来确认函数内部的先置条件和后置条件的内置assert语句的能力。
David讨论了将测试融入到Python开发中的最好方法,同时权衡了用于不同类型项目的不同风格的优势。
本文的标签:
python
标记本文!
发布日期:
2004年4月01日
级别:
初级
访问情况 1332次浏览
建议:
0 (添加评论)
平均分(共1个评分)
我要坦白一点。
尽管我是一个应用相当广泛的公共域Python库的创造者,但在我的模块中引入的单元测试是非常不系统的。
实际上,那些测试大部分是包括在gnosis.xml.pickle的GnosisUtilities中的,并由该子软件包(subpackage)的贡献者所编写。
我还发现,我下载的绝大多数第三方Python包都缺少完备的单元测试集。
不仅如此,GnosisUtilities中现有的测试也受困于另一个缺陷:
您经常需要在极其大量的细节中去推定期望的输出,以确定测试的成败。
测试实际上--在很多情况下--更像是使用库的某些部分的小实用工具。
这些测试(或实用工具)支持来自任意数据源(类型正确)的输入和/或描述性数据格式的输出。
实际上,当您需要调试一些细微的错误时,这些测试实用工具更有用。
但是对于库版本间变化的自解释的完整性检查(sanitychecks)来说,这些类测试就不能胜任了。
在这一期文章中,我尝试使用Python标准库模块doctest和unittest来改进我的实用工具集中的测试,并带领您与我一起体验(并指出一些最好的方法)。
脚本gnosis/xml/objectify/test/test_basic.py给出了一个关于当前测试的缺点及解决方案的典型示例。
下面是该脚本的最新版本:
清单1.test_basic.py
"ReadandprintandobjectifiedXMLfile"
importsys
fromgnosis.xml.objectifyimportXML_Objectify,pyobj_printer
iflen(sys.argv)>1:
forfilenameinsys.argv[1:
]:
forparserin('DOM','EXPAT'):
try:
xml_obj=XML_Objectify(filename,parser=parser)
py_obj=xml_obj.make_instance()
printpyobj_printer(py_obj).encode('UTF-8')
sys.stderr.write("++SUCCESS(using"+parser+")\n")
print"="*50
except:
sys.stderr.write("++FAILED(using"+parser+")\n")
print"="*50
else:
print"PleasespecifyoneormoreXMLfilestoObjectify."
实用工具函数pyobj_printer()生成了任意Python对象(具体说是这样一个对象,它既没有用到gnosis.xml.objectify的任何其他实用工具,也没有用到GnosisUtilities中的任何其他东西)的一个非-XML表示。
在以后的版本中,我将可能会把这个函数移到Gnosis包内的其他地方。
无论如何,pyobj_printer()使用各种类-Python的缩进和符号来描述对象和它们的属性(类似于pprint,但是扩展了实例,而不仅限于扩展内置的数据类型)。
如果一些特别的XML可能不能正确被地“对象化(objectified)”,test_basic.py脚本会提供一个很好的调试工具--您可以可视化地查看结果对象的属性和值。
此外,如果您重定向了STDOUT,您可以查看STDERR上的简单消息,如这个例子中:
清单2.分析STDERR结果消息
$pythontest_basic.pytestns.xml>/dev/null
++SUCCESS(usingDOM)
++FAILED(usingEXPAT)
不过,上面运行的例子中对成功或失败的界定很不明显:
成功只是意味着没有出现异常,而不表示(重定向的)输出正确。
使用doctest
doctest模块让您可以在文档字符串(docstrings)内嵌入注释以显示各种语句的期望行为,尤其是函数和方法的结果。
这样做很像是让文档字符串看起来如同一个交互式shell会话;完成这一任务的一个简单方法是,从一个Python交互式shell中(或者从Idel、PythonWin、MacPython或者其他带有交互式会话的IDE中)拷贝-粘贴。
这一改进的test_basic.py脚本举例说明了自诊断功能的添加:
清单3.具有自诊断功能的test_basic.py脚本
importsys
fromgnosis.xml.objectifyimportXML_Objectify,pyobj_printer,EXPAT,DOM
LF="\n"
defshow(xml_src,parser):
"""Selftestusingsimpleoruser-specifiedXMLdata
>>>xml='''
xmlversion="1.0"?
>
...
DOCTYPESpamSYSTEM"spam.dtd">
...
...Sometextabouteggs.
...OdetoSpam
...'''
>>>squeeze=lambdas:
s.replace(LF*2,LF).strip()
>>>printsqueeze(show(xml,DOM)[0])
-----*_XO_Spam*-----
{Eggs}
PCDATA=Sometextabouteggs.
{MoreSpam}
PCDATA=OdetoSpam
>>>printsqueeze(show(xml,EXPAT)[0])
-----*_XO_Spam*-----
{Eggs}
PCDATA=Sometextabouteggs.
{MoreSpam}
PCDATA=OdetoSpam
PCDATA=
"""
try:
xml_obj=XML_Objectify(xml_src,parser=parser)
py_obj=xml_obj.make_instance()
return(pyobj_printer(py_obj).encode('UTF-8'),
"++SUCCESS(using"+parser+")\n")
except:
return("","++FAILED(using"+parser+")\n")
if__name__=="__main__":
iflen(sys.argv)==1orsys.argv[1]=="-v":
importdoctest,test_basic
doctest.testmod(test_basic)
elifsys.argv[1]in('-h','-help','--help'):
print"YoumayspecifyXMLfilestoobjectifyinsteadofself-test"
print"(Use'-v'forverboseoutput,otherwisenomessagemeanssuccess)"
else:
forfilenameinsys.argv[1:
]:
forparserin(DOM,EXPAT):
output,message=show(filename,parser)
printoutput
sys.stderr.write(message)
print"="*50
注意,我在经过改进(和扩展)的测试脚本中放入了main代码块,这样,如果您在命令行中指定了XML文件,脚本将继续执行以前的行为。
这样就让您可以继续分析测试用例以外其他的XML,并只着眼于结果--或者找出gnosis.xml.objectify所做事情中的错误,或者只是理解其目的。
按标准的方式,您可以使用-h或--help参数来获得用法的说明。
当不带任何参数(或者带有只被doctest使用的-v参数)运行test_basic.py时,就会发现有趣的新功能。
在这个例子中,我们在模块/脚本自身上运行doctest--您可以看到,实际上我们将test_basic导入到脚本自己的名称空间中,这样我们可以简单地导入其他希望要测试的模块。
doctest.testmod()函数去遍历模块本身、它的函数以及它的类中的所有文档字符串,以找出所有类似交互式shell会话的内容;在这个例子中,会在show()函数中找到这样一个会话。
show()的文档字符串举例说明了在设计好的doctest会话过程中的几个小“陷阱(gotchas)”。
不幸的是,doctest在解析显式会话时,将空行作为会话结束来处理--所以,像pyobj_printer()的返回值这样的输出需要加一些保护(bemungedslightly)以进行测试。
最简单的途径是使用文档字符串本身所定义的像squeeze()这样的函数(它只是除去紧跟在后面的换行)。
此外,由于文档字符串毕竟是字符串换码(escape),所以\n这样的序列被扩展,这样使得在代码示例内部对换行进行换码稍微有一些混乱。
您可以使用\\n,不过我发现对LF的定义解决了这些问题。
在show()的文档字符串中定义的自测试所做的不仅是确保不发生异常(对照于最初的测试脚本)。
为正确的“对象化(objectification)”至少要检查一个简单的XML文档。
当然,仍然有可能不能正确地处理一些其他的XML文档--例如,上面我们试过的名称空间XML文档testns.xml遇到了EXPAT解析器失败。
由doctest处理的文档字符串可能会在其内部包含回溯(traceback),但是在特别的情况下,更好的方法是使用unittest。
回页首
使用unittest
另一个包含在gnosis.xml.objectify中的测试是test_expat.py。
创建这一测试的主要原因仅在于,使用EXPAT解析器的子软件包用户常常需要调用一个特别的设置函数来启用有名称空间的XML文档的处理(这个实际情况是演化来的而不是设计如此,并且以后可能会改变)。
老的测试会试图不借助设置去打印对象,如果发生异常则捕获之,然后如果需要的话借助设置再去打印(并给出一个关于所发生事情的消息)。
而如果使用test_basic.py,test_expat.py工具让您可以分析gnosis.xml.objectify如何去描述一个新奇的XML文档。
但是与以前一样,有很多我们可能想去验证的具体行为。
test_expat.py的一个增强的、扩展的版本使用unittest来分析各种动作执行时发生的事情,包括持有特定条件或(近似)等式的断言,或出现期望的某些异常。
看一看:
清单4.自诊断的test_expat.py脚本
"ObjectifyusingExpatparser,namespacesetupwhereneeded"
importunittest,sys,cStringIO
fromos.pathimportisfile
fromgnosis.xml.objectifyimportmake_instance,config_nspace_sep,\
XML_Objectify
BASIC,NS='test.xml','testns.xml'
classPrerequisite(unittest.TestCase):
deftestHaveLibrary(self):
"Importthegnosis.xml.objectifylibrary"
importgnosis.xml.objectify
deftest