类别|上一节(7.5装饰方法|下一节(8.2日志记录)8.1测试更多测试,更少调试(TestingRocks,DebuggingSucks)Python的动态特性使得测试对大多数程序都很有用编译器不会发现你的错误,这是唯一的方法findabugistorunthecodeandmakesureyoutryallthefeatures.断言(Assertions)assert语句用于程序内部检查,如果表达式不为True,将触发AssertionError异常assert语句语法:assert[,'Diagnosticmessage']示例:assertisinstance(10,int),'Expectedint'assert语句不应用于检查用户输入(例如,在通过Web表单输入的数据中)。assert语句旨在用于内部检查或用于不变量(条件始终为真)。合同编程(contractprogramming)也称为按合同设计(DesignByContract),自由使用断言是一种软件设计应用程序橡树。契约编程规定软件设计者应该为软件组件定义精确的接口规范。例如,您可以在所有函数输入中使用断言:defadd(x,y):assertisinstance(x,int),'Expectedint'assertisinstance(y,int),'Expectedint'returnx+y如果函数调用者没有使用正确的参数,那么检查输入可以立即捕获。>>>add(2,3)5>>>add('2','3')Traceback(mostrecentcalllast):...AssertionError:Expectedint>>>内联测试断言也可以用于简单的测试。defadd(x,y):returnx+yassertadd(2,2)==4这样,您可以将测试包含在与代码相同的模块中。奖励:如果代码明显损坏,那么尝试导入模块将导致程序崩溃。不建议将其用于详尽测试。这种方法更像是一种基本的“冒烟测试(smoketest)”。该功能是否适用于所有用例?如果不是,那么一定有问题。unittest模块假设你有一段这样的代码:#simple.pydefadd(x,y):returnx+y现在,你想测试这段代码,请像这样创建一个单独的测试文件:#test_simple.pyimportsimpleimportunittest然后定义一个测试类:#test_simple.pyimportsimpleimportunittest#注意是继承自unittest.TestCaseclassTestAdd(unittest.TestCase):...测试类必须继承自unittest.TestCase。在测试类中,定义测试方法:#test_simple.pyimportsimpleimportunittest#注意它继承自unittest.TestCaseclassTestAdd(unittest.TestCase):deftest_simple(self):#Testwithsimpleintegerargumentsr=simple.add(2,2)self.assertEqual(r,5)deftest_str(self):#测试字符串r=simple.add('hello','world')self.assertEqual(r,'helloworld')重要说明:每个方法名称必须以test开头。使用unittestunittest中内置了几个断言,每个断言诊断不同的事情。#断言expr是Trueself.assertTrue(expr)#断言x==ysertAlmostEqual(x,y)#断言x!=yself.assertNotEqual(x,y)#断言x接近yself.assertAlmostEqual(x,y,places)#Assertthatcallable(arg1,arg2,...)raisesexcself.assertRaises(exc,callable,arg1,arg2,...)以上列表不是完整列表,unittest模块还有其他断言.运行unittest要运行测试,请将您的代码转换为脚本。#test_simple.py...if__name__=='__main__':unittest.main()然后用Python执行测试文件:bash%python3test_simple.pyF.=============================================================失败:test_simple(__main__.TestAdd)------------------------------------------------------追溯(最近调用最后):文件“testsimple.py”,第8行,在test_simpleself.assertEqual(r,5)AssertionError:4!=5------------------------------------------------------在0.000sFAILED(失败=1)内进行2次测试表明高效的单元测试是一门艺术。对于大型应用程序,单元测试会变得非常复杂。unittest模块有许多与测试运行器、结果收集和其他测试方面相关的选项。有关详细信息,请参阅文档。第三方测试工具虽然内置的unittest模块的优点是可以随处使用——因为它是Python的一部分,但很多程序员也觉得unittest非常繁琐。另一个流行的测试工具是pytest。使用pytest,测试文件可以简化为如下:)=='helloworld'要运行测试,只需输入命令,例如:python-mpytest。它将找到所有测试并运行它们。pytest比这个例子要多得多。如果您决定尝试一下,通常很容易上手。练习在本练习中,我们将探讨使用Pythonunittest模块的基本机制。在上一个练习中,我们编写了一个包含Stock类的stock.py文件。对于本练习,假设我们使用练习7.9中编写的类型化属性代码(译注:typedproperty.py)。如果出于某种原因练习7.9中的代码无法运行,您可以将typedproperty.py从Solutions/7_9复制到您的工作目录中。练习8.1:编写单元测试创建一个单独的test_stock.py文件来为Stock编写一套单元测试。为了帮助您开始,这里有一小段测试用例创建:#test_stock.pyimportunittestimportstockclassTestStock(unittest.TestCase):deftest_create(self):s=stock.Stock('GOOG',100,490.1)self.assertEqual(s.name,'GOOG')self.assertEqual(s.shares,100)self.assertEqual(s.price,490.1)if__name__=='__main__':unittest.main()运行单元测试,你应该得到像这样的一些输出:.-------------------------------------------------------------------在0.000sOK中运行1个测试然后,编写额外的单元测试以检查以下内容:确保.cost属性返回正确的值(49010.0)。确保s.sell()方法正常工作。它应该相应地减少s.shares。确保s.shares属性只能设置为整数值。对于最后一部分,您需要检查异常的触发。一个简单的方法是使用这样的代码:):s.shares='100'目录|上一节(7.5装饰方式|下一节(8.2日志)注:完整翻译见https://github.com/codists/practical-python-zh