自动化测试之unittest框架详解

1、什么是Unittest框架?

    python自带一种单元测试框架

2、为什么使用UnitTest框架?

    >批量执行用例
    >提供丰富的断言知识
    >可以生成报告

3、核心要素

  1).TestCase(测试用例)
  2).TestSuite(测试套件)
  3).TestRunner(测试执行,执行TestUite测试套件的)
  4).TestLoader(批量执行测试用例-搜索指定文件夹内指定字母开头的模块) 【推荐】
  5) Fixture(固定装置(两个固定的函数,一个初始化时使用,一个结束时使用))

接下来会展开 核心要素来认识unittest框架:

首先介绍下unittest的用例规则:

​ 1、测试文件必须导包:import unittest

​ 2、测试类必须继承 unittest.TestCase

​ 3、测试方法必须以 test_开头

一、TestCase(测试用例)

1、是一个代码文件,在代码文件中来书写真正的用例代码 (里面的print均是模拟测试用例)

  1. # 1、导包

  2. # 2、自定义测试类

  3. # 3、在测试类中书写测试方法 采用print 简单书写测试方法

  4. # 4、执行用例

  5. import unittest

  6. # 2、自定义测试类,需要继承unittest模块中的TestCase类即可

  7. class TestDemo(unittest.TestCase):

  8. # 书写测试方法,测试用例代码,书写要求,测试方法必须test_ 开头

  9. def test_method1(self):

  10. print('测试方法1-1')

  11. def test_method2(self):

  12. print('测试方法1-2')

  13. # 4、执行测试用例

  14. # 4.1 光标放在类后面执行所有的测试用例

  15. # 4.2 光标放在方法后面执行当前的方法测试用例

说明:def 定义的test_ 是测试用例,只有执行 if __name__ == '___mian___' 的时候会执行测试用例,其他普通函数则不执行,通过 self 来调用执行。

二、TestSuite(测试套件)和TestRunner(测试执行)

1、TestSuite(测试套件):用来组装,打包 ,管理多个TestCase(测试用例)文件的

2、TestRunner(测试执行):用来执行 TestSuite(测试套件的)

代码:首先要准备多个测试用例的文件才可以实现TestSuite和TestRunner,以下代码是已经准备了unittest_Demo2和unittest_Demo1两个测试用例文件

  1. # 1、导包

  2. # 2、实例化(创建对象)套件对象

  3. # 3、使用套件对象添加用例方法

  4. # 4、实例化对象运行

  5. # 5、使用运行对象去执行套件对象

  6. import unittest

  7. from unittest_Demo2 import TestDemo

  8. from unittest_Demo1 import Demo

  9. suite = unittest.TestSuite()

  10. # 将⼀个测试类中的所有⽅法进⾏添加

  11. # 套件对象.addTest(unittest.makeSuite(测试类名))

  12. suite.addTest(unittest.makeSuite(TestDemo))

  13. suite.addTest(unittest.makeSuite(Demo))

  14. # 4、实例化运行对象

  15. runner = unittest.TextTestRunner();

  16. # 5、使用运行对象去执行套件对象

  17. # 运⾏对象.run(套件对象)

  18. runner.run(suite)

三、TestLoader(测试加载)

说明:

1. 将符合条件的测试方法添加到测试套件中
2. 搜索指定目录文件下指定字母开头的模块文件下test开始的方法,并将这些方法添加到测试套件中,最后返回测试套件
3. 与Testsuite功能一样,对他功能的补充,用来组装测试用例

一般测试用例是写在Case这个文件夹里面,当测试用例超多的时候就可以考虑 TestLoader

  1. 写法:

  2. 1. suite = unittest.TestLoader().discover("指定搜索的目录文件","指定字母开头模块文件")

  3. 2. suite = unittest.defaultTestLoader.discover("指定搜索的目录文件","指定字母开头模块文件") 【推荐】

  4. 注意:

  5. 如果使用写法1,TestLoader()必须有括号。

 
  1. # 1. 导包

  2. # 2. 实例化测试加载对象并添加用例 ---> 得到的是 suite 对象

  3. # 3. 实例化 运行对象

  4. # 4. 运行对象执行套件对象

  5. import unittest

  6. # 实例化测试加载对象并添加用例 ---> 得到的是 suite 对象

  7. # unittest.defaultTestLoader.discover('用例所在的路径', '用例的代码文件名')

  8. # 测试路径:相对路径

  9. # 测试文件名:可以使用 * 通配符,可以重复使用

  10. suite = unittest.defaultTestLoader.discover('./Case', 'cs*.py')

  11. runner = unittest.TextTestRunner()

  12. runner.run(suite)

  13. TestSuite与TestLoader区别:

  14. 共同点:都是测试套件

  15. 不同点:实现方式不同

  16. TestSuite: 要么添加指定的测试类中所有test开头的方法,要么添加指定测试类中指定某个test开头的方法

  17. TestLoader: 搜索指定目录下指定字母开头的模块文件中以test字母开头的方法并将这些方法添加到测试套件中,最后返回测试套件

四、Fixture(测试夹具)

是一种代码结构,在某些特定情况下,会自动执行。

4.1 方法级别

在每个测试方法(用例代码)执行前后都会自动调用的结构

def setUp(),每个测试方法执行之前都会执行 (初始化)
def tearDown(),每个测试方法执行之后都会执行 (释放)

特性:几个测试函数,执行几次。每个测试函数执行之前都会执行 setUp,执行之后都会执行tearDwon

 
  1. # 初始化

  2. def setUp(self):

  3. # 每个测试方法执行之前执行的函数

  4. pass

  5. # 释放

  6. def tearDown(self):

  7. # 每个测试方法执行之后执行的函数

  8. pass

 
  1. 场景:当你要登录自己的用户名账户的时候,都会输入网址,当你准备不用这个页面了,都会关闭当前页面;

  2. 1、输入网址 (方法级别)

  3. 2、关闭当前页面 (方法级别)

4.2 类级别

在每个测试类中所有方法执行前后 都会自动调用的结构(在整个类中 执行之前执行之后各一次)

def setUpClass() ,类中所有方法之前
def tearDownClass(),类中所有方法之后

特性:测试类运行之前运行一次setUpClass ,类运行之后运行一次tearDownClass

注意:类方法必须使用 @classmethod修饰

 
  1. @classmethod

  2. def setUpClass(cls):

  3. print('-----------1.打开浏览器')

  4. @classmethod

  5. def tearDownClass(cls):

  6. print('------------5、关闭浏览器')

场景:你上网的整个过程都首先需要打开浏览器,关闭浏览器,而他们整个过程都需要执行一次,那么就可以用类级别。

案列模板:结合了类级别和方法级别实现的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GBxQV2uP-1647245316010)(C:/Users/15277/AppData/Roaming/Typora/typora-user-images/image-20220303153824329.png)]

  1. 提示:

  2. 无论使用函数级别还是类级别,最后常用场景为:

  3. 初始化:

  4. 1. 获取浏览器实例化对象

  5. 2. 最大化浏览器

  6. 3. 隐式等待

  7. 结束:

  8. 关闭浏览器驱动对象

五、断言 ☆

1、什么是断言

让程序代替人工自动的判断预期结果和实际结果是否相符

断言的结果:

​ 1)、True,用例通过

​ 2)、False,代码抛出异常,用例不通过

​ 3)、在unittest中使用断言,需要通过 self.断言方法

2、为什么要断言

​ 自动化脚本执行时都是无人值守,需要通过断言来判断自动化脚本的执行是否通过

​ 注:自动化脚本不写断言,相当于没有执行测试一个效果。

3、常用的断言

 
  1. self.assertEqual(ex1, ex2) # 判断ex1 是否和ex2 相等

  2. self.assertIn(ex1, ex2) # ex2是否包含 ex1 注意:所谓的包含不能跳字符

  3. self.assertTrue(ex) # 判断ex是否为True

  4. 重点讲前两个assertEqual 和 assertIn

  5. 方法:

  6. assertEqual:self.assertEqual(预期结果,实际结果) 判断的是预期是否相等实际

  7. assertIn:self.assertIn(预期结果,实际结果) 判断的是预期是否包含实际中

  8. assertIn('admin', 'admin') # 包含

  9. assertIn('admin', 'adminnnnnnnn') # 包含

  10. assertIn('admin', 'aaaaaadmin') # 包含

  11. assertIn('admin', 'aaaaaadminnnnnnn') # 包含

  12. assertIn('admin', 'addddddmin') # 不是包含

 
  1. # Login 函数我已经封装好了,这里直接导包调用就可以了。

  2. import unittest

  3. from login import Login

  4. class TestLogin(unittest.TestCase):

  5. """正确的用户名和密码: admin, 123456, 登录成功"""

  6. def test_success(self):

  7. self.assertEqual('登录成功', Login('admin', '123456'))

  8. def test_username_error(self):

  9. """错误的用户名: root, 123456, 登录失败"""

  10. self.assertEqual('登录失败', Login('root', '123456'))

  11. def test_password_error(self):

  12. """错误的密码: admin, 123123, 登录失败"""

  13. self.assertEqual('登录失败', Login('admin', '123123'))

  14. def test_error(self):

  15. """错误的用户名和错误的密码: aaa, 123123, 登录失败"""

  16. # self.assertEqual('登录失败',Login('登陆失败','123123'))

  17. self.assertIn('失败', Login('登录失败', '123123'))

六、跳过

对于一些未完成的或者不满足测试条件的测试函数和测试类, 不想执行,可以使用跳过

  1. """

  2. 使用方法,装饰器完成

  3. 代码书写在 TestCase 文件

  4. """

  5. # 直接将测试函数标记成跳过

  6. @unittest.skip('跳过条件')

  7. # 根据条件判断测试函数是否跳过 , 判断条件成立, 跳过

  8. @unittest.skipIf(判断条件,'跳过原因')

 
  1. import unittest

  2. version = 20

  3. class TestDemo1(unittest.TestCase):

  4. @unittest.skip('直接跳过')

  5. def test_method1(self):

  6. print('测试用例1-1')

  7. @unittest.skipIf(version > 19, '版本大于19,测试跳过')

  8. def test_method2(self):

  9. print('测试用例1-2')

结果:

七、数据驱动(unittest ddt)☆

ddt:data-driver tests

数据驱动: 是以数据来驱动整个测试用例的执行, 也就是测试数据决定测试结果

数据驱动解决的问题是:

1)、代码和数据分离,避免代码冗余

2)、不写重复的代码逻辑;

在python解释器中需要安装 ddt 这个包才能用:

要检查是否安装上,在cmd当中 输入 pip list命名,有ddt说明安装成功

语法:

1、使用数据驱动,要在class前加上修饰器 @ddt

说明:方法里面使用 print ,为了方便,模拟测试用例,主要是为了学习数据驱动,实际中方法里面写的是测试用例的代码

  1. import unittest

  2. from ddt import ddt, data

  3. @ddt

  4. class TestDemo(unittest.TestCase):

  5. # 单一参数

  6. @data('17611110000', '17611112222')

  7. def test_1(self, phone):

  8. print('测试一电话号码:', phone)

  9. if __name__ == '__main__':

  10. unittest.main()

  11. else:

  12. pass

1)、结合 selenium 使用 ddt

  1. """

  2. unittest + selenium

  3. """

  4. import unittest

  5. from time import sleep

  6. from ddt import ddt, data

  7. from selenium import webdriver

  8. @ddt

  9. class TestBaidu(unittest.TestCase):

  10. def setUp(self) -> None:

  11. self.driver = webdriver.Chrome()

  12. self.driver.get('https://www.sogou.com/')

  13. def tearDown(self) -> None:

  14. sleep(3)

  15. self.driver.quit()

  16. # 单一参数

  17. @data('易烊千玺', '王嘉尔')

  18. def test_01(self, name):

  19. self.driver.find_element_by_id('query').send_keys(name)

  20. self.driver.find_element_by_id('stb').click()

  21. if __name__ == '__main__':

  22. unittest.main()

self:相当于java中的this,当前对象的引用,self.driver定义了driver这个变量。

2、在实际中不可能是单一参数进行传参,将会使用多个参数进行传参:

  1. 注意事项:

  2. 1)、多个数据传参的时候@data里面是要用列表形式

  3. 2)、会用到 @unpack 装饰器 进行拆包,把对应的内容传入对应的参数;

  4. import unittest

  5. from ddt import ddt, data, unpack

  6. @ddt

  7. class TestDemo(unittest.TestCase):

  8. # 多参数数据驱动

  9. @data(['admin', '123456'])

  10. # unpack 是进行拆包,不然会把列表里面的数据全部传到username这个一个参数,我们要实现列表中的两个数据分别传入对应的变量中

  11. @unpack

  12. def test_2(self, username, password):

  13. print('测试二:', username, password)

  14. if __name__ == '__main__':

  15. unittest.main()

  16. else:

  17. pass

但是以上步骤都是数据在代码当中的,假如要测试n个手机号这样的数据,全部写在 @data 装饰器里面就很麻烦,这就引出了数据驱动里面的代码和数据的分离。

3、将数据放入一个文本文件中,从文件读取数据, 如JSON、 excel、 xml、 txt等格式文件 ,这里演示的是json文件类型.

json文件处理, 这个链接介绍了json文件和Python文件基本操作

(1)在json文件驱动

  1. [

  2. {

  3. "username": "admin",

  4. "password": "123456"

  5. },

  6. {

  7. "username": "normal",

  8. "password": "45678"

  9. }

  10. ]

(2)在测试代码中读取json文件

  1. import json

  2. import unittest

  3. from ddt import ddt, data, unpack

  4. # 用json多个参数读取

  5. def reads_phone():

  6. with open('user.json', encoding='utf-8') as f:

  7. result = json.load(f) # 列表

  8. return result

  9. @ddt

  10. class TestDemo(unittest.TestCase):

  11. # 多参数数据驱动

  12. @data(*reads_phone())

  13. # unpack 是进行拆包,不然会把列表里面的数据全部传到username这个一个参数,我们要实现列表中的两个数据分别传入对应的变量中

  14. @unpack

  15. def test_2(self, username, password):

  16. print('测试二:', username, password)

  17. if __name__ == '__main__':

  18. unittest.main()

  19. else:

  20. pass

  1. 注意事项:

  2. 1、with open里面默认是 ”r“

  3. 2、@data 里面的 * 含义是实现每个json对象单个传入方法执行,不然会吧json文件里面所用数据全部传入

  4. > * 是元祖;

  5. > ** 是字典;

  6. 3、参数不能传错,要对应

执行结果:

(3)txt文件驱动
一行表示一组:

  1. admin,123456

  2. normal,456789

  3. import unittest

  4. def read():

  5. lis = []

  6. with open('readtext.txt', 'r', encoding='utf-8') as f:

  7. for line in f.readlines():

  8. # lis.append(line) # ['admin,123456\n', 'normal,456789\n']

  9. # lis.append(line.strip('\n')) ['admin,123456', 'normal,456789'] 两个字符串

  10. lis.append(line.strip('\n').split(',')) # [['admin', '123456'], ['normal', '456789']]

  11. return lis

  12. class TestDome(unittest.TestCase):

  13. def test_01(self):

  14. li = read()

  15. print(li)

  16. if __name__ == '__main__':

  17. unittest.main()

  1. """

  2. split():一个字符串里面用某个字符分割,返回列表

  3. strip():去掉两边的字符或者字符串,默认删除空白符(包括'\n', '\r', '\t', ' ')

  4. """

运行

运行

(4)csv 文件驱动

  1. 供应商名称,联系人,移动电话

  2. 英业达,张三,13261231234

  3. 阿里巴巴,李四,13261231231

  4. 日立公司,王五,13261231233

写法一:

  1. """

  2. 编写 csvv.py脚本读取csv中的测试数据

  3. """

  4. import csv

  5. class ReadCsv():

  6. def read_csv(self):

  7. lis = []

  8. # 用csv的API的reader方法!!!!

  9. data = csv.reader(open('testdata.csv', 'r')) #!!!!

  10. next(data, None)

  11. for line in data:

  12. lis.append(line)

  13. # lis.append(line[0]) # 二维数组可以省略行,列不可以省略

  14. # lis.append(line[1])

  15. return lis

  16. # 实例化类

  17. readCsv = ReadCsv()

  18. # 打印类中的方法

  19. print(readCsv.read_csv())

写法二: 推荐

  1. def csvTest():

  2. li = []

  3. with open('user.csv', 'r', encoding='utf-8') as f:

  4. filename = csv.reader(f)

  5. next(filename, None)

  6. for r in filename:

  7. li.append(r)

  8. return li

(5)yaml文件驱动

  1. -

  2. username: admin9

  3. password: 123456

  4. -

  5. username: normal

  6. password: 789456

对应的json文件

  1. [

  2. {

  3. "username": "admin9",

  4. "password": 123456

  5. },

  6. {

  7. "username": "normal",

  8. "password": 7894

  9. }

  10. ]

写法:

  1. """

  2. 使用yaml数据驱动

  3. """

  4. import unittest

  5. from time import sleep

  6. from selenium import webdriver

  7. from ddt import ddt, data, unpack, file_data

  8. @ddt

  9. class YamlTest(unittest.TestCase):

  10. def setUp(self) -> None:

  11. self.driver = webdriver.Chrome()

  12. self.driver.get('file:///D:/%E6%A1%8C%E9%9D%A2/page/%E6%B3%A8%E5%86%8CA.html')

  13. self.driver.maximize_window()

  14. def tearDown(self) -> None:

  15. driver = self.driver

  16. sleep(3)

  17. driver.quit()

  18. # file_data 传入多个参数的时候,@unpack 的解包不起作用

  19. @unittest.skip

  20. @file_data('../user.yaml')

  21. @unpack

  22. def test_yaml01(self, username, password):

  23. driver = self.driver

  24. driver.find_element_by_id('userA').send_keys(username)

  25. driver.find_element_by_id('passwordA').send_keys(password)

  26. # 注意:传的参数名称要与yaml文件对应

  27. # 在yaml数据中文件中采用对象(键值对)的方式来定义数据内容

  28. @file_data('../user1.yaml')

  29. def test_yaml02(self, username, password):

  30. driver = self.driver

  31. driver.find_element_by_id('userA').send_keys(username)

  32. driver.find_element_by_id('passwordA').send_keys(password)

  33. if __name__ == '__main__':

  34. unittest.main()

注意:file_date 装饰器,可以直接读取yaml和json文件

(6)Excel文件驱动
建立excel表的时候需要退出pychram在根目录下创建excel表保存,否则会报错

  1. def read_excel():

  2. xlsx = openpyxl.load_workbook("../excel.xlsx")

  3. sheet1 = xlsx['Sheet1']

  4. print(sheet1.max_row) # 行

  5. print(sheet1.max_column) # 列

  6. print('=======================================================')

  7. allList = []

  8. for row in range(2, sheet1.max_row + 1):

  9. rowlist = []

  10. for column in range(1, sheet1.max_column + 1):

  11. rowlist.append(sheet1.cell(row, column).value)

  12. allList.append(rowlist)

  13. return allList

用excel登录csdn操作

  1. """

  2. 测试excel数据驱动

  3. """

  4. import unittest

  5. from time import sleep

  6. import openpyxl as openpyxl

  7. from ddt import ddt, data, unpack

  8. from selenium import webdriver

  9. # 读取excel表中的数据,使用xlrd,openpyxl

  10. def read_excel():

  11. xlsx = openpyxl.load_workbook("../excel.xlsx")

  12. sheet1 = xlsx['Sheet1']

  13. print(sheet1.max_row) # 行

  14. print(sheet1.max_column) # 列

  15. print('=======================================================')

  16. allList = []

  17. for row in range(2, sheet1.max_row + 1):

  18. rowlist = []

  19. for column in range(1, sheet1.max_column + 1):

  20. rowlist.append(sheet1.cell(row, column).value)

  21. allList.append(rowlist)

  22. return allList

  23. @ddt

  24. class ExcelText(unittest.TestCase):

  25. def setUp(self) -> None:

  26. self.driver = webdriver.Chrome()

  27. self.driver.get('https://passport.csdn.net/login?code=applets')

  28. self.driver.maximize_window()

  29. def tearDown(self) -> None:

  30. driver = self.driver

  31. sleep(3)

  32. driver.quit()

  33. @data(*read_excel())

  34. @unpack

  35. def test_excel01(self, flag, username, password):

  36. print(flag, username, password)

  37. driver = self.driver

  38. sleep(2)

  39. driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[1]/span[4]').click()

  40. driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/div/div[1]/div/input').send_keys(username)

  41. driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/div/div[2]/div/input').send_keys(password)

  42. driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[2]/div[1]/div/div[2]/div/div[4]/button').click()

  43. if __name__ == '__main__':

  44. unittest.main()

八、截图操作

用例不可能每一次运行都成功,肯定运行时候有不成功的时候。如果可以捕捉到错误,并且把错误截图保存,这将
是一个非常棒的功能,也会给我们错误定位带来方便

截图方法:driver.get_screenshot_as_file

  1. """

  2. 捕捉异常截图测试

  3. """

  4. import os.path

  5. import time

  6. import unittest

  7. from time import sleep

  8. from selenium import webdriver

  9. class ScreeshotTest(unittest.TestCase):

  10. def setUp(self) -> None:

  11. self.driver = webdriver.Chrome()

  12. self.driver.get('https://www.sogou.com/')

  13. self.driver.maximize_window()

  14. def tearDown(self) -> None:

  15. sleep(3)

  16. driver = self.driver

  17. driver.quit()

  18. def test_01(self):

  19. driver = self.driver

  20. driver.find_element_by_id('query').send_keys("易烊千玺")

  21. driver.find_element_by_id('stb').click()

  22. sleep(3)

  23. print(driver.title)

  24. try:

  25. self.assertEqual(driver.title, u"搜狗一下你就知道", msg="不相等")

  26. except:

  27. self.saveScreenShot(driver, "shot.png")

  28. sleep(5)

  29. def saveScreenShot(self, driver, filename):

  30. if not os.path.exists("./imge"):

  31. os.makedirs("./imge")

  32. # 格式十分重要,小写大写敏感 %Y%m%d-%H%M%S

  33. now = time.strftime("%Y%m%d-%H%M%S", time.localtime(time.time()))

  34. driver.get_screenshot_as_file("./imge/" + now + "-" + filename)

  35. sleep(3)

  36. if __name__ == '__main__':

  37. unittest.main()

九、测试报告

有两种测试报告:

1、自带的测试报告

2、生成第三方测试报告

9.1 自带测试报告

只有单独运行 TestCase 的代码,才会生成测试报告

 

 

9.2 生成第三方测试报告

这里需要第三方的测试运行类模块,然后放在代码的目录中

就像这两个模块一样放进代码目录中

  1. 步骤:

  2. 1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中

  3. 2. 导包 unittest

  4. 3. 使用 套件对象, 加载对象 去添加用例方法

  5. 4. 实例化 第三方的运行对象 并运行 套件对象

  6. HTMLTestRunner()

写法一:

 
  1. import unittest

  2. from HTMLTestRunner import HTMLTestRunner

  3. suite = unittest.defaultTestLoader.discover('.', 'Uni*.py')

  4. file = 'report1.html'

  5. with open(file, 'wb') as f:

  6. runner = HTMLTestRunner(f, 2, '测试报告', 'python3.10') # 运行对象

  7. # 运行对象执行套件, 要写在 with 的缩进中

  8. runner.run(suite)

写法二:

  1. """

  2. 生成测试报告

  3. """

  4. import os.path

  5. import sys

  6. import time

  7. import unittest

  8. from time import sleep

  9. from HTMLTestRunner import HTMLTestRunner

  10. def createsuite():

  11. discovers = unittest.defaultTestLoader.discover("./cases", pattern="cs*.py")

  12. print(discovers)

  13. return discovers

  14. if __name__ == '__main__':

  15. # 当前路径

  16. # sys.path 是一个路径的集合

  17. curpath = sys.path[0]

  18. print(sys.path)

  19. print(sys.path[0])

  20. # 当前路径文件resultreport不存在时,就创建一个

  21. if not os.path.exists(curpath+'/resultreport'):

  22. os.makedirs(curpath+'/resultreport')

  23. # 2、解决重名问题

  24. now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))

  25. print(time.time())

  26. print(time.localtime(time.time()))

  27. # 文件名是 路径 加上 文件的名称

  28. filename = curpath+'/resultreport/'+now+'resultreport.html'

  29. # 打开文件html,是用wb以写的方式打开

  30. with open(filename, 'wb') as f:

  31. runner = HTMLTestRunner(f, 2, u"测试报告", u"测试用例情况")

  32. suite = createsuite()

  33. runner.run(suite)

这里面的当前路径也可以用 ./来表示!!!

  1. """

  2. 生成测试报告

  3. """

  4. import os.path

  5. import sys

  6. import time

  7. import unittest

  8. from time import sleep

  9. from HTMLTestRunner import HTMLTestRunner

  10. def createsuite():

  11. discovers = unittest.defaultTestLoader.discover("./cases", pattern="cs*.py")

  12. print(discovers)

  13. return discovers

  14. if __name__ == '__main__':

  15. # 当前路径文件resultreport不存在时,就创建一个

  16. if not os.path.exists('./resultreport'):

  17. os.makedirs('./resultreport')

  18. # 2、解决重名问题

  19. # 格式十分重要 %Y-%m-%d-%H %M %S

  20. now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))

  21. print(time.time())

  22. print(time.localtime(time.time()))

  23. # 文件名是 路径 加上 文件的名称

  24. filename = './resultreport/'+now+'resultreport.html'

  25. # 打开文件html,是用wb以写的方式打开

  26. with open(filename, 'wb') as f:

  27. runner = HTMLTestRunner(f, 2, u"测试报告", u"测试用例情况")

  28. suite = createsuite()

  29. runner.run(suite)

注意:

实例化 第三方的运行对象,HTMLTestRunner()的初始化有多种可以自定义设置

  1. HTMLTestRunner()

  2. 1、stream=sys.stdout, 必填,测试报告的文件对象(open ), 注意点,要使用 wb 打开

  3. 2、verbosity=1, 可选, 报告的详细程度,默认 1 简略, 2 详细

  4. 3、title=None, 可选, 测试报告的标题

  5. 4、description=None 可选, 描述信息, Python 的版本, pycharm 版本

最后生成结果:

​unittest框架就本上就是这些知识了,里面记得东西很多,多敲代码,形成记忆,自动化测试后面还剩下selenium,selenium完了过后基本上自动化的内容差不多就结束了。

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/787364.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于Qt模型插入最后一行数据中存在未填满的项,点击导致崩溃的解决办法

在使用Qt模型视图框架的时候,你可能会遇见这种情况:给QTableView设置设置模型的时候,网模型里面插入数据,因为数据是一行一行插入的,即要使用model的appandRow函数,但有时候最后一行数据没有填满一行&#…

汇川CodeSysPLC教程03-2-14 与HMI通信

硬件连接 PLC与HMI连接采用何种连接方式,通常是参考双方支持哪些接口。PLC(可编程逻辑控制器)与HMI(人机界面)之间的通讯方式主要有以下几种: 串行通讯(Serial Communication)&…

Docker-compse的应用

1 docker-compose # 使用了docker 面临一个比较大的问题,如果一个djagno项目,使用mysql,redis,不要一次性把所有服务都放到一个容器中,每个服务一个容器,批量的管理多个容器,比较难以操作&…

第5章-组合序列类型

#全部是重点知识,必须会。 了解序列和索引|的相关概念 掌握序列的相关操作 掌握列表的相关操作 掌握元组的相关操作 掌握字典的相关操作 掌握集合的相关操作1,序列和索引 1,序列是一个用于存储多个值的连续空间,每一个值都对应一…

红酒的秘密配方:如何调配出个性化的口感?

在红酒的世界里,每一滴都蕴藏着大自然的秘密和酿酒师的匠心。那些令人陶醉的口感、迷人的色泽和香气,都是经过精心调配和时光酝酿的结果。今天,就让我们一起揭开红酒调配的神秘面纱,探索如何调配出个性化的口感,感受雷…

【LeetCode】生命游戏

目录 一、题目二、解法完整代码 一、题目 根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一…

Nacos2.X 配置中心源码分析:客户端如何拉取配置、服务端配置发布客户端监听机制

文章目录 Nacos配置中心源码总流程图NacosClient源码分析获取配置注册监听器 NacosServer源码分析配置dump配置发布 Nacos配置中心源码 总流程图 Nacos2.1.0源码分析在线流程图 源码的版本为2.1.0 ,并在配置了下面两个启动参数,一个表示单机启动&#…

源码编译安装 LAMP

源码编译安装 LAMP Apache 网站服务基础Apache 简介安装 httpd 服务器 httpd 服务器的基本配置Web 站点的部署过程httpd.conf 配置文件 构建虚拟 Web 主机基于域名的虚拟主机基于IP 地址、基于端口的虚拟主机 MySQL 的编译安装构建 PHP 运行环境安装PHP软件包设置 LAMP 组件环境…

数据挖掘——matplotlib

matplotlib概述 Mat指的是Matlab,plot指的是画图,lib即library,顾名思义,matplotlib是python专门用于开发2D图表的第三方库,使用之前需要下载该库,使用pip命令即可下载。 pip install matplotlib1、matpl…

Nuxt框架中内置组件详解及使用指南(四)

title: Nuxt框架中内置组件详解及使用指南(四) date: 2024/7/9 updated: 2024/7/9 author: cmdragon excerpt: 摘要:本文详细介绍了Nuxt 3框架中的两个内置组件:和的使用方法与示例。用于捕获并处理客户端错误,提供…

【漏洞复现】29网课交单平台 SQL注入

声明:本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动,将与本文档的作者或发布者无关。 一、漏洞描述 29网课交单平台是一个在线学习平台,用于帮助学生完成网络课程的学习任务。这个平台提供了包括…

过滤器与拦截器区别、应用场景介绍

我们在进行 Web 应用开发时,时常需要对请求进行拦截或处理,故 Spring 为我们提供了过滤器和拦截器来应对这种情况。 那么两者之间有什么不同呢?本文将详细讲解两者的区别和对应的使用场景。 过滤器 过滤器是一种在 Java Web 应用中用于处理…

Celery,一个实时处理的 Python 分布式系统

大家好!我是爱摸鱼的小鸿,关注我,收看每期的编程干货。 一个简单的库,也许能够开启我们的智慧之门, 一个普通的方法,也许能在危急时刻挽救我们于水深火热, 一个新颖的思维方式,也许能…

Start LoongArch64 Alpine Linux VM on x86_64

一、Build from source(build on x86_64) Obtain the latest libvirt, virt manager, and QEMU source code, compile and install them 1.1 Build libvirt from source sudo apt-get update sudo apt-get install augeas-tools bash-completion debhelper-compat dh-apparmo…

Python学习笔记33:进阶篇(二十二)pygame的使用之image模块

前言 基础模块的知识通过这么长时间的学习已经有所了解,更加深入的话需要通过完成各种项目,在这个过程中逐渐学习,成长。 我们的下一步目标是完成python crash course中的外星人入侵项目,这是一个2D游戏项目。在这之前&#xff…

Codeforces Round 954 (Div. 3) F. Non-academic Problem

思路&#xff1a;考虑缩点&#xff0c;因为是无向图&#xff0c;所以双连通分量缩完点后是一棵树&#xff0c;我们去枚举删除每一条树边的答案&#xff0c;然后取最小值即可。 #include <bits/stdc.h>using namespace std; const int N 3e5 5; typedef long long ll; …

Profibus转ModbusTCP网关模块实现Profibus_DP向ModbusTCP转换

Profibus和ModbusTCP是工业控制自动化常用的二种通信协议。Profibus是一种串口通信协议&#xff0c;它提供了迅速靠谱的数据传输和各种拓扑结构&#xff0c;如总线和星型构造。Profibus可以和感应器、执行器、PLC等各类设备进行通信。 ModbusTCP是一种基于TCP/IP协议的通信协议…

Clickhouse的联合索引

Clickhouse 有了单独的键索引&#xff0c;为什么还需要有联合索引呢&#xff1f;了解过mysql的兄弟们应该都知道这个事。 对sql比较熟悉的兄弟们估计看见这个联合索引心里大概有点数了&#xff0c;不过clickhouse的联合索引相比mysql的又有些不一样了&#xff0c;mysql 很遵循最…

Springboot各个版本维护时间

Springboot各个版本维护时间

【 正己化人】 把自己做好,能解决所有问题

阳明先生说&#xff1a;与朋友一起辩论学问&#xff0c;纵然有人言辞观点浅近粗疏&#xff0c;或者是炫耀才华、显扬自己&#xff0c;也都不过是毛病发作。只要去对症下药就好&#xff0c;千万不能怀有轻视别人的心理&#xff0c;因为那不是君子与人为善的心。 人会爱发脾气、…