IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> 软件测试框架之——unittest -> 正文阅读

[开发工具]软件测试框架之——unittest

通过unittest创建测试
1必须继承与unittest.TestCase类
2可以定义setUp和tearDown方法,也可以定义setUpClass、tearDownClass的类方法
3所有的测试方法必须以test开头。测试方法会在运行时自动被调用
4可用pycharm自带的unittest框架运行,也可以以普通方式运行

Python复制代码

import unittest


class Demo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass方法只运行一次")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass方法只运行一次")

    def setUp(self):
        print("setUp在每个test方法执行之前执行")

    def tearDown(self):
        print("tearDown在每个test方法执行之后执行")

    def testFunc(self):
        print("这是一个测试方法")

    def testLogin(self):
        print("这是一个测试登录的方法")


if __name__ == '__main__':
    print("普通的测试入口")
    unittest.main()

运行方式的设置
●pycharm自带的unittest框架测试
●从main方法的入口开启的unittest测试

Python复制代码

if __name__ == '__main__':
    print("普通的测试入口")
    # main方法的入口开启测试
    unittest.main()

Run/DebugConfigurations

Name:

Allowparallelrun

unittest-demo-01

Storeasprojectfile

mAN方法作为入口开启测试的配置

Python

Configuration

Logs

时STPythondocs

E:python-studylautotestunittest-demopy

Docutilstask

Scriptpath.:

ASTSphinxtask

Parameters

Pythontests

Autodetect

Environment

-demo.py

Doctests

st-demo.D

PYTHONUNBUFFERED-1

Environmentvariables

Nosetests

pytest

不走main方法,使用自带的unittest进行测试

Twisted

Unittests

lnterpreteroptions

ShellScript

的配置,默认是这种配置

SpaceTask

cipython-studyautotest

tOx

AddcontentrootstoPYTHONPATH

AddsourcerootstoPYTHONPATH

Execution

Emulateterminalinoutputconsole

RunwithPythonConsole

Redirectinputfrom:

Editconfigurationtemplates..

OK

Apply

Cancel

1631018738(1).png


pycharm自带的unittest框架测试
这种运行测试,main方法就不会生效。
上面的代码输出结果为:

Plain Text复制代码

setUpClass方法只运行一次
setUp在每个test方法执行之前执行
这是一个测试方法
tearDown在每个test方法执行之后执行
setUp在每个test方法执行之前执行
这是一个测试登录的方法
tearDown在每个test方法执行之后执行
tearDownClass方法只运行一次
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

设置从main方法的入口开启unittest测试
上面的输出结果为,这个就会走if?__name__ ==?'__main__':中的代码

Plain Text复制代码

普通的测试入口
setUpClass方法只运行一次
setUp在每个test方法执行之前执行
这是一个测试方法
tearDown在每个test方法执行之后执行
setUp在每个test方法执行之前执行
这是一个测试登录的方法
tearDown在每个test方法执行之后执行
tearDownClass方法只运行一次
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK


断言
断言一旦失败了,后面的代码就不会执行
常用的断言有:
●self.assertEqual()
●self.assertNotEqual()
●self.assertIn()
●self.assertNotIn()
●self.assertTrue()
●self.assertFalse()
断言的结果表示
●点.代表断言正确
●F代表断言失败
●E代表代码有错误

实现断言失败后再截图功能
●通过异常处理的方式实现
●通过装饰器的方式实现

通过异常处理的方式

Python复制代码

import time
import unittest
from selenium import webdriver

from ddt import ddt, data, unpack
from util import Util


@ddt
class Demo(unittest.TestCase):
    
    # 其他方法省略

    def test_demo1(self):
        try:
            self.assertEqual(1, 2)
        except AssertionError as e:
            import os, time
            day = time.strftime('%Y%m%d', time.localtime(time.time()))
            sceenshot_path = os.getcwd() + r'\reports\screenshot_%s' % day
            if not os.path.exists(sceenshot_path):
                os.makedirs(sceenshot_path)

            tm = time.strftime('%H%M%S', time.localtime(time.time()))
            print(sceenshot_path + '\\{}_{}.png'.format('screen_shot', tm))
            self.driver.get_screenshot_as_file(sceenshot_path + '\\{}_{}.png'.format('screen_shot', tm))
            # 将异常继续抛出给unittest
            raise e


通过装饰器的方式

Python复制代码

import time
import unittest
from selenium import webdriver

from ddt import ddt, data, unpack
from util import Util


@ddt
class Demo(unittest.TestCase):

    # 省略一些方法

    def addpic(func):
        def wrapper(self, *args, **kwargs):
            try:
                func(self, *args, **kwargs)
            except AssertionError as e:
                import os, time
                day = time.strftime('%Y%m%d', time.localtime(time.time()))
                sceenshot_path = os.getcwd() + r'\reports\screenshot_%s' % day
                if not os.path.exists(sceenshot_path):
                    os.makedirs(sceenshot_path)

                tm = time.strftime('%H%M%S', time.localtime(time.time()))
                print(sceenshot_path + '\\{}_{}.png'.format('screen_shot', tm))
                self.driver.get_screenshot_as_file(sceenshot_path + '\\{}_{}.png'.format('screen_shot', tm))
                # 将异常继续抛出给unittest
                raise e
        return wrapper

    @addpic
    def test_demo1(self):
        self.assertEqual(1, 2)




if __name__ == '__main__':
    print("普通的测试入口")

TestLoader
自动化用例管理 TestLoader类的常见方法:
●loadTestFromTestCase():从一个python类中加载
●loadTestFromTestModule(): 从一个python文件中加载
●loadTestFromTestNames():从方法名中加载
●discover:从一个路径中加载

loadTestsFromTestCase

Python复制代码

from stringtest import StringTest
from numbertest import NumberTest
import unittest

if __name__ == '__main__':
    st = unittest.defaultTestLoader.loadTestsFromTestCase(StringTest)
    nt = unittest.defaultTestLoader.loadTestsFromTestCase(NumberTest)
    # 将TestCase装到TestSuite中
    suite = unittest.TestSuite([st,nt])
    # 使用TestRunner运行TestSuite中的所有用例
    unittest.TextTestRunner().run(suite)

loadTestsFromModule

Python复制代码

import unittest
import stringtest
import numbertest

if __name__ == '__main__':
    names = [numbertest, stringtest]
    modules = []
    for item in names:
        module = unittest.defaultTestLoader.loadTestsFromModule(item)
        modules.append(module)
    suite = unittest.TestSuite(modules)
    unittest.TextTestRunner().run(suite)

loadTestFromTestNames

Python复制代码

from stringtest import StringTest
import unittest


def getFullTestCaseName():
    pass


if __name__ == '__main__':
    names = ['stringtest.StringTest.test1', 'autotest.numbertest.NumberTest.test2']
    smoke_test = unittest.defaultTestLoader.loadTestsFromNames(names)
    suite = unittest.TestSuite([smoke_test])
    unittest.TextTestRunner().run(suite)

获取一个类中的所有用例getTestCaseNames

Python复制代码

# 获取一个类中的所有的用例
cases = unittest.defaultTestLoader.getTestCaseNames(StringTest)
print(cases)


discover

Python复制代码

case_dir = 'autotest'
# smoke代表冒烟测试的文件夹,加载冒烟测试文件夹下的所有测试用例
dis = unittest.defaultTestLoader.discover(case_dir + '/smoke', pattern='*.py')
suite = unittest.TestSuite(dis)
unittest.TextTestRunner().run(suite)


生成测试报告
使用HTMLTestRunner生成测试报告
1配置方法(将HTMLTestRunner_cn.py放到python的安装目录的site-packages目录下)
2生成测试报告
3在报告中添加截图图片
4失败重试功能
?

Python复制代码

from HTMLTestRunner import HTMLTestRunner

# 保存图片,写在需要保存图片的用例中
self.imgs.append(self.driver.get_screenshot_as_base64())

# 组装TestSuite
st = unittest.defaultTestLoader.loadTestsFromTestCase(StringTest)
nt = unittest.defaultTestLoader.loadTestsFromTestCase(NumberTest)
suite = unittest.TestSuite([st, nt])

runner = HTMLTestRunner(title='测试报告1', description='第一次生成测试报告', 
                        stream=open('test-report.html', 'wb'), verbosity=2)

# 有的版本还可携带retry=2, save_last_try=False参数。这里我下载的HTMLTestRunner版本中没有这两个参数
# retry代表断言失败重试的最大次数,中间如果成功,就不再重试。
# save_last_try代表是否只保留最后一次重试的记录,True表示只保留一次,False表示保留每一次重试的记录

runner.run(suite)
    


参数化驱动测试用例
所谓参数化,是指利用不同的测试数据来测试相同的场景,为了提高代码的重用性,增加代码效率而采用一种代码编写的方法,叫参数化,也就是数据驱动。达到测试数据和测试业务相分离的效果。
换句话说,就是通过传参的不同,一个方法可以运行多个测试用例,减少代码的冗余,提高代码的复用率。

普通的循环
使用循环来在一个方法中跑多个测试用例,虽然能减少代码的冗余,但实际上在生成的测试报告中,算一个用例,这是不好的。

Python复制代码

import time
import unittest
from selenium import webdriver


class Demo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass方法只运行一次")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass方法只运行一次")

    def setUp(self):
        print("setUp在每个test方法执行之前执行")
        self.driver = webdriver.Chrome
        self.url = '某个url地址'
        self.testdata = [
            ('', 'admin123', 'user id 不能为空'),
            ('admin', '', 'password不能为空'),
            ('adminx', 'admin123', '没有此用户'),
            ('admin', 'xxxx', '密码错误')
        ]

    def tearDown(self):
        print("tearDown在每个test方法执行之后执行")

    def testFunc(self):
        print("这是一个测试方法")
        self.assertTrue(False)

    def testLogin(self):
        print("这是一个测试登录的方法")
        self.driver.get(self.url)
        time.sleep(1)
        for data in self.testdata:
            time.sleep(1)
            self.driver.find_element_by_id('username').clear()
            self.driver.find_element_by_id('username').send_keys(data[0])
            time.sleep(1)
            self.driver.find_element_by_id('password').clear()
            self.driver.find_element_by_id('password').send_keys(data[1])
            time.sleep(1)
            self.driver.find_element_by_xpath('//input[@value="Login"]').click()
            time.sleep(1)
            errmsg = self.driver.find_element_by_xpath('//div[contains(text(),"{}")]'.format(data[2])).text
            self.assertEqual(errmsg, data[2])
            self.driver.find_element_by_xpath('//span[contains(text(),"确定")]').click()


if __name__ == '__main__':
    print("普通的测试入口")
    unittest.main()


在unittest框架中使用参数化
1安装ddt: pip install ddt
2导入相关的模块:from ddt import ddt,data,unpack
3参数化的几种形式
a参数值为单个的参数形式
b参数值为组合参数形式
c从函数中返回参数值
d从文件中返回参数值

参数值为单个的参数形式

Python复制代码

import time
import unittest
from selenium import webdriver

from ddt import ddt, data, unpack

# 这个注解是必须的
@ddt
class Demo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass方法只运行一次")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass方法只运行一次")

    def setUp(self):
        print("setUp在每个test方法执行之前执行")
       
    def tearDown(self):
        print("tearDown在每个test方法执行之后执行")

    # 单个注解的传参形式
    @data(1, 2, 3)
    def test_data(self, value):
        print(value)

参数值为多个的形式

Python复制代码

import time
import unittest
from selenium import webdriver

from ddt import ddt, data, unpack


@ddt
class Demo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass方法只运行一次")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass方法只运行一次")

    def setUp(self):
        print("setUp在每个test方法执行之前执行")
        self.driver = webdriver.Chrome
        self.url = '某个url地址'
        
    def tearDown(self):
        print("tearDown在每个test方法执行之后执行")


    @data(
        ('', 'admin123', 'user id 不能为空'),
        ('admin', '', 'password不能为空'),
        ('adminx', 'admin123', '没有此用户'),
        ('admin', 'xxxx', '密码错误')
    )
    # 表示将元组的每一行作为一条数据
    @unpack
    def testLogin2(self, username, password, err):
        print("username={},password={},err={}".format(username, password, err))

    @data(
        ('', 'admin123', 'user id 不能为空'),
        ('admin', '', 'password不能为空'),
        ('adminx', 'admin123', '没有此用户'),
        ('admin', 'xxxx', '密码错误')
    )
    @unpack
    def testLogin(self, username, password, err):
        print("这是一个测试登录的方法")
        self.driver.get(self.url)
        time.sleep(1)
        self.driver.find_element_by_id('username').clear()
        self.driver.find_element_by_id('username').send_keys(username)
        time.sleep(1)
        self.driver.find_element_by_id('password').clear()
        self.driver.find_element_by_id('password').send_keys(password)
        time.sleep(1)
        self.driver.find_element_by_xpath('//input[@value="Login"]').click()
        time.sleep(1)
        errmsg = self.driver.find_element_by_xpath('//div[contains(text(),"{}")]'.format(err)).text
        self.assertEqual(errmsg, err)
        self.driver.find_element_by_xpath('//span[contains(text(),"确定")]').click()


if __name__ == '__main__':
    print("普通的测试入口")
    unittest.main()


从函数中传来参数值
定义外部函数:

Python复制代码

class Util:

    @classmethod
    def get_data(cls):
        testdata = [
            ('', 'admin123', 'user id 不能为空'),
            ('admin', '', 'password不能为空'),
            ('adminx', 'admin123', '没有此用户'),
            ('admin', 'xxxx', '密码错误')
        ]
        return testdata

Python复制代码

import time
import unittest
from selenium import webdriver

from ddt import ddt, data, unpack
# 导入外部函数所在的类
from util import Util



@ddt
class Demo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass方法只运行一次")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass方法只运行一次")

    def setUp(self):
        print("setUp在每个test方法执行之前执行")
        self.driver = webdriver.Chrome
        self.url = '某个url地址'
        self.testdata = [
            ('', 'admin123', 'user id 不能为空'),
            ('admin', '', 'password不能为空'),
            ('adminx', 'admin123', '没有此用户'),
            ('admin', 'xxxx', '密码错误')
        ]

    def tearDown(self):
        print("tearDown在每个test方法执行之后执行")

    #
    # @data(1, 2, 3)
    # def test_data(self, value):
    #     print(value)

    @data(*Util.get_data())
    @unpack
    def testLogin2(self, username, password, err):
        print("username={},password={},err={}".format(username, password, err))



if __name__ == '__main__':
    print("普通的测试入口")
    unittest.main()


从文件中传来参数值
data.txt文件

Python复制代码

, admin123, user id 不能为空
admin, , password不能为空
adminx, admin123, 没有此用户
admin, xxxx, 密码错误

Python复制代码

class Util:
    @classmethod
    def get_data_from_file(cls, path):
        rows = []
        with open(path, 'r', encoding='utf-8') as f:
            for line in f:
                user_data = line.strip().split(',')
                rows.append(user_data)
        return rows

Python复制代码

import time
import unittest
from selenium import webdriver

from ddt import ddt, data, unpack
from util import Util



@ddt
class Demo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print("setUpClass方法只运行一次")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass方法只运行一次")

    def setUp(self):
        print("setUp在每个test方法执行之前执行")
        self.driver = webdriver.Chrome
        self.url = '某个url地址'

    def tearDown(self):
        print("tearDown在每个test方法执行之后执行")


    @data(*Util.get_data_from_file('data.txt'))
    # @data(*Util.get_data())
    @unpack
    def testLogin2(self, username, password, err):
        print("username={},password={},err={}".format(username, password, err))



if __name__ == '__main__':
    print("普通的测试入口")
    unittest.main()

?如果对python自动化测试、web自动化、接口自动化、移动端自动化、大型互联网架构技术、面试经验交流等等感兴趣的老铁们,可以关注我。我会在公众号(程序员阿沐)/群里(810119819)不定期的发放免费的资料链接,这些资料都是从各个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处之后分享给大家。欢迎分享,欢迎评论,欢迎转发。需要资料的同学可以关注我获取资料链接。

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-10-26 12:23:30  更:2021-10-26 12:23:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 22:58:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码