python中的单元测试-如果不测试代码则在python中进行单元测试没有人会_第1页
python中的单元测试-如果不测试代码则在python中进行单元测试没有人会_第2页
python中的单元测试-如果不测试代码则在python中进行单元测试没有人会_第3页
python中的单元测试-如果不测试代码则在python中进行单元测试没有人会_第4页
python中的单元测试-如果不测试代码则在python中进行单元测试没有人会_第5页
已阅读5页,还剩4页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

python中的单元测试_如果不测试代码,则在python中进⾏单元测试没有⼈会python中的单元测试Catchbugsbeforeyouevenwritethem甚⾄在编写错误之前就将其捕获Pythonisamulti-purposelanguagethatisusedforeverythingbackend.Inthisarticle,IwillteachyoutoperformbasicunittestinginPython,howtomockmodules,andmakesureyourcodeisclean.Python是⼀种⽤于所有后端的多⽤途语⾔。在本⽂中,我将教您使⽤Python执⾏基本的单元测试,如何模拟模块并确保代码⼲净。什么是单元测试?(WhatisUnit-testing?)Unit-testingisoneofthewaystotestyourcode.Otherwaysincludefunctionaltesting,integrationtesting,regressiontestingandsoon.Testingisvitaltoanylargercodebase,asitletsyouiterateandperformchangesquickly,withoutworryingtomuchaboutwhatisgoingtobreak.单元测试是测试代码的⽅法之⼀。其他⽅式包括功能测试,集成测试,回归测试等等。测试对于任何更⼤的代码库都是⾄关重要的,因为它使您可以快速迭代并执⾏更改,⽽不必担⼼会发⽣什么。Unit-testingisthelowesttestingmethodontheabstractionlevel.Unit-testingisconcernedwithtestingindividualmodulesandfunctionsinisolation.Thatis,bymakingsureallthepartsofyoursystemworkcorrectly,youcanmaketheassumptionthatthewholesystemisworkingok.单元测试是抽象级别上最低的测试⽅法。单元测试是关于隔离测试单独的模块和功能。也就是说,通过确保系统的所有部分正常⼯作,您可以假设整个系统都可以正常⼯作。Thatis,inidealworld,ofcourse.Whileunit-testingisveryvaluable,thewholesystemisnotmerelyasumofitsparts:evenifeveryfunctionisworkingasintended,youwillstillneedtotesthowwelldotheyfittogether(whichisoutofscopeofthisarticle).就是说,在理想世界中。尽管单元测试⾮常有价值,但是整个系统不仅仅是其各个部分的总和:即使每个功能都按预期⼯作,您仍然需要测试它们之间的配合程度(这超出了本⽂的范围))。单元测试与TDD有何关系?(HowdoesUnit-testingrelatetoTDD?)Unit-testingisoneofthefoundationsofTDD.TDDstandsforTestDrivenDevelopment,andisamethodologyforproducingqualitysoftware.Inessence,itallboilsdowntothese:单元测试是TDD的基础之⼀。TDD代表“测试驱动开发”,是⼀种⽣产⾼质量软件的⽅法。从本质上讲,这全都归结为以下⼏点:1.Writetestsfirst.Thinkabouthowdifferentpartsofyoursystemworkinisolationandwriteteststhatvalidatetheirintendedbehaviour.Yourtestsmustfail,becauseyouhavenotwrittenanyactualcodeyet.⾸先编写测试。考虑⼀下系统的不同部分如何隔离⼯作,并编写验证其预期⾏为的测试。测试必须失败,因为您尚未编写任何实际代码。2.Writejustenoughcodetomakethetestspass.编写⾜够的代码以使测试通过。3.Refactorwhatyoujustwrote.重构您刚刚写的内容。4.Gotostep1.转到步骤1。Thatisit!Thewholecycletakesacoupleofminutes,butthissimpletechniquewillmakesureyoursystemis(1)workingaccordingtothespecsand(2)istestable.ButtogetstartedwithTDD,youneedtomasterbasicunit-testingfirst.这就对了!整个周期需要花费⼏分钟,但是这种简单的技术将确保您的系统(1)根据规范⼯作,并且(2)是可测试的。但是要开始使⽤TDD,您需要⾸先掌握基本的单元测试。unittest模块(unittestmodule)Unit-testinginPythonisavailableoutoftheboxwiththeunittestmodule.Wewilllearnunit-testingbydevelopingourownfactorialfunction.Togetstarted,openanewPythonfileaddwritethiscodeitit:Python中的单元测试可与unittest模块⼀起使⽤。我们将通过开发我们⾃⼰的阶乘函数来学习单元测试。⾸先,打开⼀个新的Python⽂件,添加以下代码:importunittestclassMyTestCase(unittest.TestCase):deftest_something(self):self.assertEqual(True,False)if__name__=='__main__':unittest.main()Online1youcannoticetheimportedunittestmodule.Onlines4-6wedefineatestcasebyextendingtheTestCaseclass.Init,weonlyhave1testatthemoment,thetest_something.Itisimportantthattestsareprefixedwithtest_,sothatthetestrunnercanfindthem.Finally,onlines9-10weexecutethetests.Ifyoutryrunningthisfilenow,thetestwillfail:在第1⾏上,您可以注意到导⼊的unittest模块。在第4-6⾏,我们通过扩展TestCase类来定义测试⽤例。其中,我们⽬前只有1个测试,即test_something。重要的是,测试必须以test_作为前缀,以便测试运⾏器可以找到它们。最后,在9-10⾏,我们执⾏测试。如果尝试⽴即运⾏此⽂件,则测试将失败:======================================================================FAIL:test_something(__main__.MyTestCase)----------------------------------------------------------------------Traceback(mostrecentcalllast):File"main.py",line6,intest_somethingself.assertEqual(True,False)AssertionError:True!=False----------------------------------------------------------------------Ran1testin0.001sFAILED(failures=1)Thatishappeningbecauseonline6weareassertingthatTrueandFalseareequal,whichisobviouslyfalse.Let'schangethattotestour(unwritten!)function:之所以会这样,是因为在第6⾏中,我们断⾔True和False相等,这显然是错误的。让我们更改它以测试我们的(未编写!)功能:classFactorialTestCase(unittest.TestCase):deftest_factorial(self):result=factorial(3)self.assertEqual(result,6)Ifyourunthisnow,itwillstillfail,becausewedidnotwritethefactorialfunctionyet.Let'smakethistestpass:如果您现在运⾏此命令,它将仍然会失败,因为我们尚未编写factorial函数。让我们通过这个测试:deffactorial(num):return6Whilethisisnotmathematicallysound,thismakesourtestpass.Let’swritesomemoretests:尽管这在数学上并不合理,但这使我们的测试通过了。让我们再写⼀些测试:deftest_factorial(self):self.assertEqual(factorial(1),1)self.assertEqual(factorial(2),2)self.assertEqual(factorial(3),6)self.assertEqual(factorial(10),3628800)Checkthatthetestsnowfail(sincefactorialreturns6allthetime)andmakethechangestothefactorialfunction:检查测试现在是否失败(因为factorial始终返回6),并对阶乘函数进⾏更改:deffactorial(num):ifnum==1:return1returnnum*factorial(num-1)And,ifyourunthis,thetestspass:⽽且,如果运⾏此命令,则测试通过:Ran1testin0.002sOKNow,let’stakeastepbackandunderstandwhatwejustdid.现在,让我们退后⼀步,了解我们刚才所做的事情。断⾔(Assertions)Whenwewritetests,wewanttotestforsomething.Ifsomethingisequal,ornotequal,ifafunctionthrowsanexception,ifamethodwascalledwithcertainparameters,etc.Suchchecksarecalledassertions.Assertionsarethingsthatarealwayssupposedtobetrueforthecodetoworkproperly.编写测试时,我们想测试⼀些东西。如果相等或不相等,则函数抛出异常,使⽤特定参数调⽤⽅法等。此类检查称为断⾔。断⾔是为了使代码正常⼯作⽽总是应该做的事情。OneassertionyoujustsawiftheassertEqual.Itchecksthat2variablespassedinareequaltoeachother.assertEqualisavailablethroughself,andisprovidedbytheTestCaseparentclass.Herearesomeofthecommonassertionsyouwillfinduseful:您刚刚看到了⼀个断⾔是否为assertEqual。它检查传⼊的2个变量是否相等。assertEqual通过self可⽤,由TestCase⽗类提供。以下是⼀些有⽤的常见断⾔:assertEqual(x,y)/assertNotEqual(x,y)assertEqual(x,y)/assertNotEqual(x,y)assertTrue(x)/assertFalse(x)assertTrue(x)/assertFalse(x)assertIs(x,y)assertIs(x,y)assertIsNone(x)assertIsNone(x)assertIn(x,y)assertIn(x,y)assertIsInstance(x,y)/assertNotIsInstance(x,y)assertIsInstance(x,y)/assertNotIsInstance(x,y)assertRaises(exc,fun,*args,**kwargs)assertRaises(exc,fun,*args,**kwargs)assertGreater(x,y)/assertLess(x,y)/assertGreaterEqual(x,y)/assertLessEqual(x,y)assertGreater(x,y)/assertLess(x,y)/assertGreaterEqual(x,y)/assertLessEqual(x,y)Someoftheseareavailableusingacontextmanager,likeassertRaises.Itmakesthecodeabiteasiertoread:其中⼀些可以使⽤上下⽂管理器来使⽤,例如assertRaises。它使代码更易于阅读:withself.assertRaises(Exception):do_something_that_throws("please")Usingtheseassertionsyoucantestprettymuchanything!使⽤这些断⾔,您⼏乎可以测试任何东西!模拟(Mocking)Recallthatunittestingistestingindividualpartsofsysteminisolation.But,thisisneverthecasewiththesystemswedesign.Differentpartsdependonotherparts,andtomaketestingpossibleyousometimesneedtomockthemout.Forexample,ifyouaretestingthebehaviourofanHTTPresponseparser,thereisnoneedtoperformanactualHTTPresponse:allyouneedtodoitmockit.回想⼀下,单元测试在隔离测试系统的各个部分。但是,我们设计的系统从来没有这种情况。不同的部分取决于其他部分,为了使测试成为可能,您有时需要将它们模拟出来。例如,如果您正在测试HTTP响应解析器的⾏为,则⽆需执⾏实际的HTTP响应:只需对其进⾏模拟即可。Mocking,then,isamethodofabstractingimplementationofsoftwaremodulesthatarenotrelevanttothebehaviouryouaretesting.Moreover,youcanassertifamockwascalled,howmanytimeswasitcalled,andwhatargumentsweresuppliedtoit.Theseadditionalassertionswill,nodoubt,makeyourtestsmorerobust.那么,模拟是⼀种抽象化与所测试⾏为⽆关的软件模块实现的⽅法。此外,您可以断⾔是否调⽤了模拟程序,调⽤了多少次以及向其提供了哪些参数。毫⽆疑问,这些额外的断⾔将使您的测试更加强⼤。MockinginPythonisalsoavailableviatheunittestmodule.Let'sstartwithasimpleexample.Supposeyouwroteafunctionthatcallsthesuppliedcallback:也可以通过unittest模块使⽤Python进⾏模拟。让我们从⼀个简单的例⼦开始。假设您编写了⼀个调⽤提供的回调的函数:defcall_this_function(func):func()Totestit,youjustneedtopassaMagicMock(availablethroughunittest.mock):要对其进⾏测试,您只需传递⼀个MagicMock(可通过unittest.mock):importunittestfromunittest.mockimportMagicMockdefcall_this_function(func):func()classCallbackTestCase(unittest.TestCase):deftest_callback(self):mock=MagicMock()call_this_function(mock)mock.assert_called_once()if__name__=='__main__':unittest.main()MagicMockisaspecialtypeofobject.Youcancallititself,callanymethodyoucancomeupwithanditwillneverthrow.Instead,itwillmemorizeallcallsandmakethemavailabletoyouthroughassertions.Notethatinthiscase,assertionsarecalledonthemockobject,insteadofself.Herearesomeoftheassertionsavailableformockobjects:MagicMock是⼀种特殊的对象。您可以调⽤它本⾝,调⽤可以使⽤的任何⽅法,并且它永远不会抛出。相反,它将记住所有调⽤,并通过断⾔使您可以使⽤它们。请注意,在这种情况下,断⾔是在mock对象上调⽤的,⽽不是self。以下是⼀些可⽤于模拟对象的断⾔:assert_calledassert_calledassert_called_onceassert_called_onceassert_called_withassert_called_withassert_called_once_withassert_called_once_withassert_not_calledassert_not_called模拟进⼝(Mockingimports)Sometimes,whenyouaretestingaclass,youneedtomockoutacertainfunctionorclassthatisimportedinit.Considerthisexample:有时,当您测试⼀个类时,您需要模拟其中导⼊的某个函数或类。考虑以下⽰例:fromsome_libraryimportapi_actiondefdo_stuff():result=api_action('/stuff')returnresultNow,totestthiscode,youwanttomocktheapi_actionfunction.Thisisactuallyveryeasytodowiththepatchdecorator(availablefromunittest.mock):现在,要测试此代码,您想模拟api_action函数。使⽤patch装饰器实际上很容易做到(可从unittest.mock):importunittestfromunittest.mockimportpatchfrommainimportdo_stuffclassApiTestCase(unittest.TestCase):@patch('main.api_action',side_effect='abacaba')deftest_stuff(self,api_action_mock):result=do_stuff()self.assertEqual(result,'abacaba')api_action_mock.assert_called_once_with('/stuff')if__name__=='__main__':unittest.main()Thepatchdecoratorisappliedtothetestfunctionthatweareworkingwith.Itacceptsasanargumentthepathtothemockedmodule.Thereisaveryimportantnotehere:youspecifythepathrelativetothetestingcode.Forexample,themain.pyfileimportedthe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论