自动化测试之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完了过后基本上自动化的内容差不多就结束了。

总结:

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

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

软件测试面试文档

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

 

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

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Python采集京东标题,店铺,销量,价格,SKU,评论,图片

京东的许多数据是通过 JavaScript 动态加载的,包括销量、价格、评论和评论时间等信息。我们无法仅通过传统的静态网页爬取方法获取到这些数据。需要使用到如 Selenium 或 Pyppeteer 等能够模拟浏览器行为的工具。 另外,京东的评论系统是独立的一个系统&a…

DOM(文档对象模型)生命周期事件

前言 DOM 生命周期事件涉及到从创建、更新到销毁 DOM 元素的不同阶段。 ● 我们来看下当HTML文档加载完再执行JavaScript代码 document.addEventListener(DOMContentLoaded, function (e) {console.log(HTML parsed adn DOM tree built!, e); })● 除此之外,浏览…

【正点原子i.MX93开发板试用连载体验】项目计划和开箱体验

本文最早发表于电子发烧友:【   】【正点原子i.MX93开发板试用连载体验】基于深度学习的语音本地控制 - 正点原子学习小组 - 电子技术论坛 - 广受欢迎的专业电子论坛! (elecfans.com)https://bbs.elecfans.com/jishu_2438354_1_1.html 有一段时间没有参加电子发…

核密度估计KDE和概率密度函数PDF(深入浅出)

目录 1. 和密度估计(KDE)核密度估计的基本原理核密度估计的公式核密度估计的应用Python中的KDE实现示例代码 结果解释解释结果 总结 2. 概率密度函数(PDF)概率密度函数(PDF)是怎么工作的:用图画…

websocket推送消息,模拟推送

上一篇文章:什么是webSocket?以及它的一些相关理论知识 背景: MQTT 的发布/订阅模式与 WebSocket 的双向通信特性相结合。 通过将 MQTT 与 WebSocket 结合使用,可以在 Web 应用中实现高效、实时的消息传输,特别适用于…

来一组爱胜品1133DN PRO打印机的照片

刚拆箱的机器正面照片 打开前盖正准备要安装原装耗材 下图是原装耗材,硒鼓型号是DR2833、碳粉盒型号是TN2833,鼓组件打印页数12000页,TN2833标准容量粉盒打印页数1600页/5%覆盖率,TN2833H大容量粉盒打印页数3000页/5%覆盖率、TN2833L超大容量…

h5 video 标签播放经过 java 使用 ws.schild( jave、ffmpeg ) 压缩后的 mp4 视频只有声音无画面的问题排查记录

1. 引入 ws.schild MAVEN 依赖&#xff1a; <dependency><groupId>ws.schild</groupId><artifactId>jave-all-deps</artifactId><version>3.5.0</version></dependency><dependency><groupId>ws.schild</grou…

SQL 与 NoSQL 数据库:一场关于灵活性与结构的对话

文章目录 引言SQL 数据库&#xff1a;传统之光定义特征优势缺点 NoSQL 数据库&#xff1a;新时代的弹性定义特征优势缺点 何时选择 NoSQL&#xff1f;场景1&#xff1a;海量数据与高并发场景2&#xff1a;灵活性需求场景3&#xff1a;实时数据分析场景4&#xff1a;分布式系统 …

2024年7月1日,公布的OpenSSH的漏洞【CVE-2024-6387】

目录 ■概要 ■概要&#xff08;日语&#xff09; ■相关知识 openssh 和 ssh 有区别吗 如何查看 openssh的版本 漏洞描述 glibc Linux是什么 如何查看系统是不是基于 Gibc RHEL Linux 是基于Glibc的Linux吗 还有哪些 Linux版本是基于 GNU C库&#xff08;glibc&…

算力狂飙|WAIC 2024上的服务器

7月7日&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;在上海落下帷幕。这场备受瞩目的AI盛宴与热辣夏日碰撞&#xff0c;吸引了全球科技、产业及学术界的广泛关注&#xff0c;线下参观人数突破30万人次&#xff0c;线上流量突…

gitlab-runner安装部署CI/CD

手动安装 卸载旧版&#xff1a; gitlab-runner --version gitlab-runner stop yum remove gitlab-runner下载gitlab对应版本的runner # https://docs.gitlab.com/runner/install/bleeding-edge.html#download-any-other-tagged-releasecurl -L --output /usr/bin/gitlab-run…

通用后台管理(二)——项目搭建

目录 前言 一、安装vue-cli依赖 1、使用yarn下载vue-cli 2、使用npm下载 3、检查一下是否下载成功 二、创建项目 1、创建项目&#xff0c;my-app是项目名称 2、 这里选择vue 2&#xff0c;蓝色表示选中的。 3、启动项目 三、下载项目依赖 四、配置项目 1、修改esli…

【从零开始实现stm32无刷电机FOC】【理论】【3/6 位置、速度、电流控制】

目录 PID控制滤波单独位置控制单独速度控制单独电流控制位置-速度-电流串级控制 上一节&#xff0c;通过对SVPWM的推导&#xff0c;我们获得了控制电机转子任意受力的能力。本节&#xff0c;我们选用上节得到的转子dq轴解耦的SVPWM形式&#xff0c;对转子受力进行合理控制&…

STM32实战篇:按键控制LED

按键控制LED 功能要求 有两个按键&#xff0c;分别控制两个LED灯。当按键按下后&#xff0c;灯的亮暗状态改变。实物如下图所示&#xff1a; 由图可知&#xff0c;按键一端直接接地&#xff0c;故另一端所对应IO引脚的输入模式应该为上拉输入模式。 实现代码 #include "…

nvm下载

nvm下载 1.下载nvm安装包2.安装nvm3.修改settings.txt4.安装成功5.继续配置 下载nvm之前,你最好将你电脑上的node卸载掉,直接在winx中卸载就行 1.下载nvm安装包 https://github.com/coreybutler/nvm-windows/releases 2.安装nvm 3.修改settings.txt root: E:\nvm\install\nv…

DMA方式的知识点笔记

苏泽 “弃工从研”的路上很孤独&#xff0c;于是我记下了些许笔记相伴&#xff0c;希望能够帮助到大家 目录 1. DMA基本概念 2. DMA传送过程 易错点 DMA控制器操作流程 3. DMA传送方式 这是单总线的结果 &#xff08;CPU说了算 所以不会产生于CPU的冲突&#xff09; 这…

新闻资讯整合平台:一站式满足企业信息需求

摘要&#xff1a; 面对信息爆炸的时代&#xff0c;企业如何在海量数据中快速获取有价值资讯&#xff0c;成为提升竞争力的关键。本文将探讨如何通过一站式新闻资讯整合平台&#xff0c;实现企业信息需求的全面满足&#xff0c;提升决策效率&#xff0c;同时介绍实用工具推荐&a…

Transformer中的编码器和解码器结构有什么不同?

Transformer背后的核心概念&#xff1a;注意力机制&#xff1b;编码器-解码器结构&#xff1b;多头注意力等&#xff1b; 例如&#xff1a;The cat sat on the mat&#xff1b; 1、嵌入&#xff1a; 首先&#xff0c;模型将输入序列中的每个单词嵌入到一个高维向量中表示&…

Vuforia AR篇(八)— AR塔防上篇

目录 前言一、设置Vuforia AR环境1. 添加AR Camera2. 设置目标图像 二、创建塔防游戏基础1. 导入素材2. 搭建场景3. 创建敌人4. 创建脚本 前言 在增强现实&#xff08;AR&#xff09;技术快速发展的今天&#xff0c;Vuforia作为一个强大的AR开发平台&#xff0c;为开发者提供了…

工业机床CNC设备如何上云?

工业机床CNC设备如何上云&#xff1f; 工业机床的计算机数控&#xff08;CNC&#xff09;设备实现远程监控数据上云&#xff0c;是现代制造业智能化转型的关键一环。这一过程不仅能够实时监测设备状态、优化生产流程&#xff0c;还能通过大数据分析提升生产效率与产品质量&…