unittest 1、什么是Unittest框架? python自带一种单元测试框架 2、为什么使用UnitTest框架? 批量执行用例 提供丰富的断言知识 可以生成报告 3、核心要素: 1)。TestCase(测试用例) 2)。TestSuite(测试套件) 3)。TestRunner(测试执行,执行TestUite测试套件的) 4)。TestLoader(批量执行测试用例搜索指定文件夹内指定字母开头的模块)【推荐】 5)。Fixture(固定装置(两个固定的函数,一个初始化时使用,一个结束时使用)) 接下来会展开核心要素来认识unittest框架: 首先介绍下unittest的用例规则: 1、测试文件必须导包:importunittest 2、测试类必须继承unittest。TestCase 3、测试方法必须以test开头 一、TestCase(测试用例) 1、是一个代码文件,在代码文件中来书写真正的用例代码(里面的print均是模拟测试用例)1、导包2、自定义测试类3、在测试类中书写测试方法采用print简单书写测试方法4、执行用例importunittest2、自定义测试类,需要继承unittest模块中的TestCase类即可classTestDemo(unittest。TestCase):书写测试方法,测试用例代码,书写要求,测试方法必须test开头deftestmethod1(self):print(测试方法11)deftestmethod2(self):print(测试方法12)4、执行测试用例4。1光标放在类后面执行所有的测试用例4。2光标放在方法后面执行当前的方法测试用例 说明:def定义的test是测试用例,只有执行ifnamemian的时候会执行测试用例,其他普通函数则不执行,通过self来调用执行。 二、TestSuite(测试套件)和TestRunner(测试执行) 1、TestSuite(测试套件):用来组装,打包,管理多个TestCase(测试用例)文件的 2、TestRunner(测试执行):用来执行TestSuite(测试套件的) 代码:首先要准备多个测试用例的文件才可以实现TestSuite和TestRunner,以下代码是已经准备了unittestDemo2和unittestDemo1两个测试用例文件1、导包2、实例化(创建对象)套件对象3、使用套件对象添加用例方法4、实例化对象运行5、使用运行对象去执行套件对象importunittestfromunittestDemo2importTestDemofromunittestDemo1importDemosuiteunittest。TestSuite()将个测试类中的所有法进添加套件对象。addTest(unittest。makeSuite(测试类名))suite。addTest(unittest。makeSuite(TestDemo))suite。addTest(unittest。makeSuite(Demo))4、实例化运行对象runnerunittest。TextTestRunner();5、使用运行对象去执行套件对象运对象。run(套件对象)runner。run(suite) 三、TestLoader(测试加载) 说明: 将符合条件的测试方法添加到测试套件中 2。搜索指定目录文件下指定字母开头的模块文件下test开始的方法,并将这些方法添加到测试套件中,最后返回测试套件 3。与Testsuite功能一样,对他功能的补充,用来组装测试用例 一般测试用例是写在Case这个文件夹里面,当测试用例超多的时候就可以考虑TestLoader写法:1。suiteunittest。TestLoader()。discover(指定搜索的目录文件,指定字母开头模块文件)2。suiteunittest。defaultTestLoader。discover(指定搜索的目录文件,指定字母开头模块文件)【推荐】注意:如果使用写法1,TestLoader()必须有括号。1。导包2。实例化测试加载对象并添加用例得到的是suite对象3。实例化运行对象4。运行对象执行套件对象importunittest实例化测试加载对象并添加用例得到的是suite对象unittest。defaultTestLoader。discover(用例所在的路径,用例的代码文件名)测试路径:相对路径测试文件名:可以使用通配符,可以重复使用suiteunittest。defaultTestLoader。discover(。Case,cs。py)runnerunittest。TextTestRunner()runner。run(suite)TestSuite与TestLoader区别:共同点:都是测试套件不同点:实现方式不同TestSuite:要么添加指定的测试类中所有test开头的方法,要么添加指定测试类中指定某个test开头的方法TestLoader:搜索指定目录下指定字母开头的模块文件中以test字母开头的方法并将这些方法添加到测试套件中,最后返回测试套件 四、Fixture(测试夹具) 是一种代码结构,在某些特定情况下,会自动执行。 4。1方法级别 在每个测试方法(用例代码)执行前后都会自动调用的结构 defsetUp(),每个测试方法执行之前都会执行(初始化) deftearDown(),每个测试方法执行之后都会执行(释放) 特性:几个测试函数,执行几次。每个测试函数执行之前都会执行setUp,执行之后都会执行tearDwon初始化defsetUp(self):每个测试方法执行之前执行的函数pass释放deftearDown(self):每个测试方法执行之后执行的函数pass场景:当你要登录自己的用户名账户的时候,都会输入网址,当你准备不用这个页面了,都会关闭当前页面;1、输入网址(方法级别)2、关闭当前页面(方法级别) 4。2类级别 在每个测试类中所有方法执行前后都会自动调用的结构(在整个类中执行之前执行之后各一次) defsetUpClass(),类中所有方法之前 deftearDownClass(),类中所有方法之后 特性:测试类运行之前运行一次setUpClass,类运行之后运行一次tearDownClass 注意:类方法必须使用classmethod修饰classmethoddefsetUpClass(cls):print(1。打开浏览器)classmethoddeftearDownClass(cls):print(5、关闭浏览器)场景:你上网的整个过程都首先需要打开浏览器,关闭浏览器,而他们整个过程都需要执行一次,那么就可以用类级别。 案列模板:结合了类级别和方法级别实现的 〔外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(imgGBxQV2uP1647245316010)(C:Users15277AppDataRoamingTyporatyporauserimagesimage20220303153824329。png)〕提示:无论使用函数级别还是类级别,最后常用场景为:初始化:1。获取浏览器实例化对象2。最大化浏览器3。隐式等待结束:关闭浏览器驱动对象 五、断言 1、什么是断言: 让程序代替人工自动的判断预期结果和实际结果是否相符 断言的结果: 1)、True,用例通过 2)、False,代码抛出异常,用例不通过 3)、在unittest中使用断言,需要通过self。断言方法 2、为什么要断言: 自动化脚本执行时都是无人值守,需要通过断言来判断自动化脚本的执行是否通过 注:自动化脚本不写断言,相当于没有执行测试一个效果。 3、常用的断言:self。assertEqual(ex1,ex2)判断ex1是否和ex2相等self。assertIn(ex1,ex2)ex2是否包含ex1注意:所谓的包含不能跳字符self。assertTrue(ex)判断ex是否为True重点讲前两个assertEqual和assertIn方法:assertEqual:self。assertEqual(预期结果,实际结果)判断的是预期是否相等实际assertIn:self。assertIn(预期结果,实际结果)判断的是预期是否包含实际中assertIn(admin,admin)包含assertIn(admin,adminnnnnnnn)包含assertIn(admin,aaaaaadmin)包含assertIn(admin,aaaaaadminnnnnnn)包含assertIn(admin,addddddmin)不是包含Login函数我已经封装好了,这里直接导包调用就可以了。importunittestfromloginimportLoginclassTestLogin(unittest。TestCase):正确的用户名和密码:admin,123456,登录成功deftestsuccess(self):self。assertEqual(登录成功,Login(admin,123456))deftestusernameerror(self):错误的用户名:root,123456,登录失败self。assertEqual(登录失败,Login(root,123456))deftestpassworderror(self):错误的密码:admin,123123,登录失败self。assertEqual(登录失败,Login(admin,123123))deftesterror(self):错误的用户名和错误的密码:aaa,123123,登录失败self。assertEqual(登录失败,Login(登陆失败,123123))self。assertIn(失败,Login(登录失败,123123))六、跳过 对于一些未完成的或者不满足测试条件的测试函数和测试类,不想执行,可以使用跳过使用方法,装饰器完成代码书写在TestCase文件直接将测试函数标记成跳过unittest。skip(跳过条件)根据条件判断测试函数是否跳过,判断条件成立,跳过unittest。skipIf(判断条件,跳过原因)importunittestversion20classTestDemo1(unittest。TestCase):unittest。skip(直接跳过)deftestmethod1(self):print(测试用例11)unittest。skipIf(version19,版本大于19,测试跳过)deftestmethod2(self):print(测试用例12) 结果 七、数据驱动(unittestddt) ddt:datadrivertests 数据驱动:是以数据来驱动整个测试用例的执行,也就是测试数据决定测试结果 数据驱动解决的问题是: 1)、代码和数据分离,避免代码冗余 2)、不写重复的代码逻辑; 在python解释器中需要安装ddt这个包才能用: 要检查是否安装上,在cmd当中输入piplist命名,有ddt说明安装成功 语法: 1、使用数据驱动,要在class前加上修饰器ddt 说明:方法里面使用print,为了方便,模拟测试用例,主要是为了学习数据驱动,实际中方法里面写的是测试用例的代码 importunittestfromddtimportddt,dataddtclassTestDemo(unittest。TestCase):单一参数data(17611110000,17611112222)deftest1(self,phone):print(测试一电话号码:,phone)ifnamemain:unittest。main()else:pass 1)、结合selenium使用ddtunittestseleniumimportunittestfromtimeimportsleepfromddtimportddt,datafromseleniumimportwebdriverddtclassTestBaidu(unittest。TestCase):defsetUp(self)None:self。driverwebdriver。Chrome()self。driver。get(https:www。sogou。com)deftearDown(self)None:sleep(3)self。driver。quit()单一参数data(易烊千玺,王嘉尔)deftest01(self,name):self。driver。findelementbyid(query)。sendkeys(name)self。driver。findelementbyid(stb)。click()ifnamemain:unittest。main() self:相当于java中的this,当前对象的引用,self。driver定义了driver这个变量。 2、在实际中不可能是单一参数进行传参,将会使用多个参数进行传参:注意事项:1)、多个数据传参的时候data里面是要用列表形式2)、会用到unpack装饰器进行拆包,把对应的内容传入对应的参数;importunittestfromddtimportddt,data,unpackddtclassTestDemo(unittest。TestCase):多参数数据驱动data(〔admin,123456〕)unpack是进行拆包,不然会把列表里面的数据全部传到username这个一个参数,我们要实现列表中的两个数据分别传入对应的变量中unpackdeftest2(self,username,password):print(测试二:,username,password)ifnamemain:unittest。main()else:pass 但是以上步骤都是数据在代码当中的,假如要测试n个手机号这样的数据,全部写在data装饰器里面就很麻烦,这就引出了数据驱动里面的代码和数据的分离。 3、将数据放入一个文本文件中,从文件读取数据,如JSON、excel、xml、txt等格式文件,这里演示的是json文件类型。 json文件处理,这个链接介绍了json文件和Python文件基本操作 (1)、在json文件驱动〔{username:admin,password:123456},{username:normal,password:45678}〕 (2)、在测试代码中读取json文件importjsonimportunittestfromddtimportddt,data,unpack用json多个参数读取defreadsphone():withopen(user。json,encodingutf8)asf:resultjson。load(f)列表returnresultddtclassTestDemo(unittest。TestCase):多参数数据驱动data(readsphone())unpack是进行拆包,不然会把列表里面的数据全部传到username这个一个参数,我们要实现列表中的两个数据分别传入对应的变量中unpackdeftest2(self,username,password):print(测试二:,username,password)ifnamemain:unittest。main()else:pass注意事项:1、withopen里面默认是r2、data里面的含义是实现每个json对象单个传入方法执行,不然会吧json文件里面所用数据全部传入是元祖;是字典;3、参数不能传错,要对应 执行结果: (3)、txt文件驱动 一行表示一组:admin,123456normal,456789importunittestdefread():lis〔〕withopen(readtext。txt,r,encodingutf8)asf:forlineinf。readlines():lis。append(line)〔admin,123456,normal,456789〕lis。append(line。strip())〔admin,123456,normal,456789〕两个字符串lis。append(line。strip()。split(,))〔〔admin,123456〕,〔normal,456789〕〕returnlisclassTestDome(unittest。TestCase):deftest01(self):liread()print(li)ifnamemain:unittest。main()split():一个字符串里面用某个字符分割,返回列表strip():去掉两边的字符或者字符串,默认删除空白符(包括,r,,)(3)、csv文件驱动供应商名称,联系人,移动电话英业达,张三,13261231234阿里巴巴,李四,13261231231日立公司,王五,13261231233 写法一:编写csvv。py脚本读取csv中的测试数据importcsvclassReadCsv():defreadcsv(self):lis〔〕用csv的API的reader方法!!!!datacsv。reader(open(testdata。csv,r))!!!!next(data,None)forlineindata:lis。append(line)lis。append(line〔0〕)二维数组可以省略行,列不可以省略lis。append(line〔1〕)returnlis实例化类readCsvReadCsv()打印类中的方法print(readCsv。readcsv()) 写法二:推荐defcsvTest():li〔〕withopen(user。csv,r,encodingutf8)asf:filenamecsv。reader(f)next(filename,None)forrinfilename:li。append(r)returnli(4)、yaml文件驱动username:admin9password:123456username:normalpassword:789456 对应的json文件〔{username:admin9,password:123456},{username:normal,password:7894}〕 写法:使用yaml数据驱动importunittestfromtimeimportsleepfromseleniumimportwebdriverfromddtimportddt,data,unpack,filedataddtclassYamlTest(unittest。TestCase):defsetUp(self)None:self。driverwebdriver。Chrome()self。driver。get(file:D:E6A18CE99DA2pageE6B3A8E5868CA。html)self。driver。maximizewindow()deftearDown(self)None:driverself。driversleep(3)driver。quit()filedata传入多个参数的时候,unpack的解包不起作用unittest。skipfiledata(。。user。yaml)unpackdeftestyaml01(self,username,password):driverself。driverdriver。findelementbyid(userA)。sendkeys(username)driver。findelementbyid(passwordA)。sendkeys(password)注意:传的参数名称要与yaml文件对应在yaml数据中文件中采用对象(键值对)的方式来定义数据内容filedata(。。user1。yaml)deftestyaml02(self,username,password):driverself。driverdriver。findelementbyid(userA)。sendkeys(username)driver。findelementbyid(passwordA)。sendkeys(password)ifnamemain:unittest。main() 注意:filedate装饰器,可以直接读取yaml和json文件(4)、Excel文件驱动 建立excel表的时候需要退出pychram在根目录下创建excel表保存,否则会报错defreadexcel():xlsxopenpyxl。loadworkbook(。。excel。xlsx)sheet1xlsx〔Sheet1〕print(sheet1。maxrow)行print(sheet1。maxcolumn)列print()allList〔〕forrowinrange(2,sheet1。maxrow1):rowlist〔〕forcolumninrange(1,sheet1。maxcolumn1):rowlist。append(sheet1。cell(row,column)。value)allList。append(rowlist)returnallList 用excel登录csdn操作测试excel数据驱动importunittestfromtimeimportsleepimportopenpyxlasopenpyxlfromddtimportddt,data,unpackfromseleniumimportwebdriver读取excel表中的数据,使用xlrd,openpyxldefreadexcel():xlsxopenpyxl。loadworkbook(。。excel。xlsx)sheet1xlsx〔Sheet1〕print(sheet1。maxrow)行print(sheet1。maxcolumn)列print()allList〔〕forrowinrange(2,sheet1。maxrow1):rowlist〔〕forcolumninrange(1,sheet1。maxcolumn1):rowlist。append(sheet1。cell(row,column)。value)allList。append(rowlist)returnallListddtclassExcelText(unittest。TestCase):defsetUp(self)None:self。driverwebdriver。Chrome()self。driver。get(https:passport。csdn。netlogin?codeapplets)self。driver。maximizewindow()deftearDown(self)None:driverself。driversleep(3)driver。quit()data(readexcel())unpackdeftestexcel01(self,flag,username,password):print(flag,username,password)driverself。driversleep(2)driver。findelementbyxpath(htmlbodyp〔2〕pp〔2〕p〔2〕p〔1〕pp〔1〕span〔4〕)。click()driver。findelementbyxpath(htmlbodyp〔2〕pp〔2〕p〔2〕p〔1〕pp〔2〕pp〔1〕pinput)。sendkeys(username)driver。findelementbyxpath(htmlbodyp〔2〕pp〔2〕p〔2〕p〔1〕pp〔2〕pp〔2〕pinput)。sendkeys(password)driver。findelementbyxpath(htmlbodyp〔2〕pp〔2〕p〔2〕p〔1〕pp〔2〕pp〔4〕button)。click()ifnamemain:unittest。main()十、截图操作 用例不可能每一次运行都成功,肯定运行时候有不成功的时候。如果可以捕捉到错误,并且把错误截图保存,这将 是一个非常棒的功能,也会给我们错误定位带来方便 截图方法:driver。getscreenshotasfile捕捉异常截图测试importos。pathimporttimeimportunittestfromtimeimportsleepfromseleniumimportwebdriverclassScreeshotTest(unittest。TestCase):defsetUp(self)None:self。driverwebdriver。Chrome()self。driver。get(https:www。sogou。com)self。driver。maximizewindow()deftearDown(self)None:sleep(3)driverself。driverdriver。quit()deftest01(self):driverself。driverdriver。findelementbyid(query)。sendkeys(易烊千玺)driver。findelementbyid(stb)。click()sleep(3)print(driver。title)try:self。assertEqual(driver。title,u搜狗一下你就知道,msg不相等)except:self。saveScreenShot(driver,shot。png)sleep(5)defsaveScreenShot(self,driver,filename):ifnotos。path。exists(。imge):os。makedirs(。imge)格式十分重要,小写大写敏感YmdHMSnowtime。strftime(YmdHMS,time。localtime(time。time()))driver。getscreenshotasfile(。imgenowfilename)sleep(3)ifnamemain:unittest。main() 十一、测试报告 有两种测试报告:1、自带的测试报告 2、生成第三方测试报告9。1自带测试报告 只有单独运行TestCase的代码,才会生成测试报告 10。2生成第三方测试报告 这里需要第三方的测试运行类模块,然后放在代码的目录中 就像这两个模块一样放进代码目录中步骤:1。获取第三方的测试运行类模块,将其放在代码的目录中2。导包unittest3。使用套件对象,加载对象去添加用例方法4。实例化第三方的运行对象并运行套件对象HTMLTestRunner() 写法一:importunittestfromHTMLTestRunnerimportHTMLTestRunnersuiteunittest。defaultTestLoader。discover(。,Uni。py)filereport1。htmlwithopen(file,wb)asf:runnerHTMLTestRunner(f,2,测试报告,python3。10)运行对象运行对象执行套件,要写在with的缩进中runner。run(suite) 写法二:生成测试报告importos。pathimportsysimporttimeimportunittestfromtimeimportsleepfromHTMLTestRunnerimportHTMLTestRunnerdefcreatesuite():discoversunittest。defaultTestLoader。discover(。cases,patterncs。py)print(discovers)returndiscoversifnamemain:当前路径sys。path是一个路径的集合curpathsys。path〔0〕print(sys。path)print(sys。path〔0〕)当前路径文件resultreport不存在时,就创建一个ifnotos。path。exists(curpathresultreport):os。makedirs(curpathresultreport)2、解决重名问题nowtime。strftime(YmdHMS,time。localtime(time。time()))print(time。time())print(time。localtime(time。time()))文件名是路径加上文件的名称filenamecurpathresultreportnowresultreport。html打开文件html,是用wb以写的方式打开withopen(filename,wb)asf:runnerHTMLTestRunner(f,2,u测试报告,u测试用例情况)suitecreatesuite()runner。run(suite) 这里面的当前路径也可以用。来表示!!!生成测试报告importos。pathimportsysimporttimeimportunittestfromtimeimportsleepfromHTMLTestRunnerimportHTMLTestRunnerdefcreatesuite():discoversunittest。defaultTestLoader。discover(。cases,patterncs。py)print(discovers)returndiscoversifnamemain:当前路径文件resultreport不存在时,就创建一个ifnotos。path。exists(。resultreport):os。makedirs(。resultreport)2、解决重名问题格式十分重要YmdHMSnowtime。strftime(YmdHMS,time。localtime(time。time()))print(time。time())print(time。localtime(time。time()))文件名是路径加上文件的名称filename。resultreportnowresultreport。html打开文件html,是用wb以写的方式打开withopen(filename,wb)asf:runnerHTMLTestRunner(f,2,u测试报告,u测试用例情况)suitecreatesuite()runner。run(suite) 注意: 实例化第三方的运行对象,HTMLTestRunner()的初始化有多种可以自定义设置 HTMLTestRunner()1、streamsys。stdout,必填,测试报告的文件对象(open),注意点,要使用wb打开2、verbosity1,可选,报告的详细程度,默认1简略,2详细3、titleNone,可选,测试报告的标题4、descriptionNone可选,描述信息,Python的版本,pycharm版本 最后生成结果 unittest框架就本上就是这些知识了,里面记得东西很多,多敲代码,形成记忆。。。 希望本文对你有所帮助如果对软件测试、接口测试、自动化测试、面试经验交流感兴趣可以私聊我或关注公众号特斯汀软件测试。免费领取最新软件测试大厂面试资料和Python自动化、接口、框架搭建学习资料!技术大牛解惑答疑,同行一起交流。