selenium-pytest框架的基础学习

简介: selenium-pytest框架的基础学习

pytest是一个非常好用的测试框架,并且这个框架已经非常成熟了。

它简单灵活,容易上手,支持参数化,也能够支持简单的单元测试和复杂的功能测试。也是自动化测试的利器。

我们先来看看如何安装:在Python环境没问题的情况下直接pip install pytest即可,进入正题

命令行参数

vs

先来看一个比较简单的示例,我们直接从示例入手:

import pytest
def test_01():
    print("第一条用例")
class Testcase:
    def test_02(self):
        print("第二条测试用例")

注意看我的类名,首字母大写的!!!这里实际上是不会在控制台输出我们的打印信息的,所以我们还需要改改:

import pytest
def test_01():
    print("第一条用例")
class Testcase:
    def test_02(self):
        print("第二条测试用例")
if __name__ == '__main__':
    pytest.main(["-s","-v","running.py"])

-s是显示打印信息,-v显示详细的测试结果,这里你也可以写到一起去,也就是:

if __name__ == '__main__':
    pytest.main(["running.py","-vs"])

除了写main方法可以输出结果之外,我们开始控制台直接码命令。

可能你会遇到no tests ran in 0.01s这样的情况,这种情况一般都是目录下找不到执行文件,这时候你就需要cd 切换到文件所在的文件目录就好了。执行命令也是大同小异。

pytest running.py -vs


maxfail

当maxfail=1的时候,用例里面出现一个错误用例停止运行

接下来我们多写几个用例:

def test_01():
    print("第一条用例")
    assert 0 > 1
def test_04():
    print("清安无别事")
class Testcase:
    def test_02(self):
        print("第二条测试用例")
    def test_03(self):
        print("第三条用例")

我是在控制台码命令的,所以这里我就不写main方法去跑了。

pytest running.py -vs --maxfail=1


xdist

pip install --xdist

多线程,在用例少的情况下看不出太大的区别,多线程要比单线程少节省将近一半的时间,也就是说当xdist 为2时,启用两个线程,比直接pytest跑节省近一半时间。

def test_01():
    print("第一条用例")
def test_04():
    print("清安无别事")
class Testcase:
    def test_02(self):
        print("第二条测试用例")
    def test_03(self):
        print("第三条用例")

pytest running.py -vs --maxfail=1 -n 2,这里xdist有缩写,也就是-n,后面的2就是2个线程的意思。注意看下方截图的红色框框的位置,就是线程的名字。

reruns

pip install pytest-rerunfailures

重试运行,当运行出现错误的时候,也就是非预期结果的时候我们可以再次运行一次该用例

reruns为2时,重新运行两次

def test_01():
    print("第一条用例")
    assert 0>1
def test_04():
    print("清安无别事")
class Testcase:
    def test_02(self):
        print("第二条测试用例")
    def test_03(self):
        print("第三条用例")

pytest running.py -vs - n 2 --reruns 2,看下方的截图,重复运行的两次。

测试报告

pytest框架自带了一个测试报告生成器。--html=路径/名称.html

def test_01():
    print("第一条用例")
    assert 0>1
def test_04():
    print("清安无别事")
class Testcase:
    def test_02(self):
        print("第二条测试用例")
    def test_03(self):
        print("第三条用例")

如果我想将这四个用例生成测试报告:

pytest running.py -vs - n 2 --reruns 2 --html=report/report.html

在report文件夹下生成一个report.html报告,这个报告虽然很一般 ,也是不错了。当然我们也可以生成allure测试报告,美观一些。


allure

pip install allure-pytest下载好库。

pytest running.py -vs --alluredir ../report/xmll

allure generate --clean ../report/xmll -o ./result/html

仔细看你就会发现其实--clean后面接的是运行代码时-o后面的路径,因为运行pytest running.py -vs --alluredir ../report/xmll后,文件下会自行创建一个report文件,用例运行信息会存在xmll里面,我们生成报告就需要调用里面的信息。

因为我是控制台输出的所以需要这两行代码,输出完后就可以在result文件下看到一个index.html文件,就是测试报告了。如下图所示:

mark标签

什么是mark标签?mark标签分为内置标签与外置标签,可以用来对用例进行管理运行,我们直接看看例子:

def test002():
    print('这是一条最优级别的用例')
def test005():
    print("skip_reason")
def test003():
    print('这是一条严重级别的用例')
def test006():
    print("006冒烟")
def test004():
    print('这是一条较严重级别的用例')

上述例子的情况下,与正常情况下无异,这里需要注意:

pytest与unittest不一样,我test序列号写的很乱,如果是在unittest中的话肯定就是按数字的顺序来执行了,pytest中不分先后,05在04用例的前面,那么就得按这顺序来,先运行05用例再04用例。

那么我们给这里加上mark标签看看:

def test002():
    print('这是一条最优级别的用例')
def test005():
    print("005冒烟")
@pytest.mark.qingan
def test003():
    print('这是一条严重级别的用例')
def test006():
    print("006冒烟")
@pytest.mark.qinganan
def test004():
    print('这是一条较严重级别的用例')

猜猜这里运行几条用例?3条,没错。

注意:这里mark标签是外置标签,我自己命名的。看看运行结果:

pytest -m qingan test_speack.py -sv这里指定外置标签的标签名。不指定就会运行全部的用例,不指定怎么对用例进行管理。

这里还是可以看到只执行了两条,也就是标签的那两条用例。这里对指定用例进行标记运行。

mark标签会受外界的装饰器影响吗?我们来看看。

def func(function):
    def fn(*args,**kwargs):
        print("this is "+function.__name__)
        return function(*args,**kwargs)
    return fn
# ----------上面是自己写的装饰器--------------
@func
def test002():
    print('这是一条最优级别的用例')
# @pytest.mark.skip
def test005():
    print("skip_reason")
@pytest.mark.qingan
@func
def test003():
    print('这是一条严重级别的用例')
def test006():
    print("006冒烟")
@pytest.mark.qingan
@func
def test004():
    print('这是一条较严重级别的用例')

是不会的,也是遵循pytest强大的执行顺序来的。

那么看了自定义标签,看看内置标签吧:

def func(function):
    def fn(*args,**kwargs):
        print("this is "+function.__name__)
        return function(*args,**kwargs)
    return fn
# ----------上面是自己写的装饰器--------------
@func
def test002():
    print('这是一条最优级别的用例')
@pytest.mark.skip
def test005():
    print("skip_reason")
@pytest.mark.qingan
@func
def test003():
    print('这是一条严重级别的用例')
def test006():
    print("006冒烟")
@pytest.mark.qingan
@func
def test004():
    print('这是一条较严重级别的用例')

我在05用例处添加了一个内置标签,这里需要注意的是,执行命令不一样:

pytest test_speack.py -s -rs或者pytest -k qingan test_speack.py -sv

05被跳过了,我们可以更改内置标签的提示信息

@pytest.mark.skip(reason='不运行')
def test005():
    print("skip_reason")

控制台就会有这样的一条信息可以看到。

这里可以看到自定义标签与内置标签处用的运行命令有所不同,不同之处在于一个用了-m一个用了-k。

使用-m的时候我们需要指定自定义标签,才能跑用例,否则跑不起来,如果用-k即使不指定也是可以跑起来,这样的一个好处,相信不说你也知道了,控制用例执行,可以更好的执行你想执行的用例。更好的是用于冒烟测试。

另外还有一个也就是内置标签判断,skipif。这是一个怎么样的标签呢?

看skip后面带的if就知道了,可以做一个判断!条件为真则跳过运行,条件为假则运行用例。

@func
def test002():
    print('这是一条最优级别的用例')
@pytest.mark.skipif(1>2,reason='不运行')
def test005():
    print("skip_reason")
@pytest.mark.qingan
@func
def test003():
    print('这是一条严重级别的用例')
def test006():
    print("006冒烟")
@pytest.mark.qingan
@func
def test004():
    print('这是一条较严重级别的用例')

pytest -k test_speack.py -sv我在用例005处写了一个skipif的判断,1>2是FALSE,所以此处不跳过。

所以此处为真的条件就不举例了,此处直接告诉各位答案了。


前置后置

在unittest你肯定看到过setup这一类的函数,看下面的例子

class Testcasse():
    """前置后置"""
    def setup(self):
        print("1每个用例的前置")
    def teardown(self):
        print("2每个用例的后置")
    def setup_class(self):
        print("3所有用例的前置")
    def teardown_class(self):
        print("4所有用例的后置")
    def test_004(self):
        print("004")
    def test_005(self):
        print("005")

其中的顺序是怎么样的呢。是否跟之前说的全部无优先级呢?运行一下就知道了。

这里就很明显了,优先级是3124,这里别误会,我在print里面加了数字,说一 这里就这样简写了。下面两个用例004,005是用于分辨的,不然运行不起来。各位可以自己跑一跑。这与pytest本身的规则有关系。


fixture

这里很容易弄错写成fixtrue,所以需要注意一些。怎么用呢?fixture可以实现我们在pytest的用例中调佣其他函数,可以发现我们使用fixture是在被调用函数之上添加我们的fixture。看例子:

@pytest.fixture
def login():
    print("login")
    return "运行用例"
def test_seacher():
    print(login)    # 返回的是一个地址
    print(f"搜索用户名{login}")
def test_seacher1(login):
    print(login)
    print(f"搜索用户名{login}")

pytest text_fixtrue.py -sv运行起来看看效果:

这样看就不难理解了。这是一种简单的距离,看起来像是调用。

fixture区别于unnitest的传统单元测试(setup/teardown)有显著改进。

fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function

               -function:每一个函数或方法都会调用

               -class:每一个类调用一次,一个类中可以有多个方法

               -module:每一个.py文件调用一次,该文件内又有多个function和class

               -session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module

这里就需要用到了conftest.py配置了。可以实现数据共享,比如py跨文件共享前置,另外需要注意的是conftest.py脚本名称是固定的,不更改名称。pytest会自动寻找这个文件。

如果此文件放到项目的根目录下就可以全局调用了,如果放到某个package下,那就在改package内有效。

在根目录下这是conftest下的内容:

@pytest.fixture(scope='function')
def openbrowser():
    print("打开浏览器")
@pytest.fixture(scope='session')
def qingan():
    print("我是清安")

这是某个文件内的demo下的内容,主要看Testcase中的内容:

@pytest.fixture(scope='session')
def login():
    print("登录方法")
    # return "浏览器"
    # 此处当scope等于function时,yield可以作用于全局
    yield "类似于teardown,用法可以跟return一样"
def testSQL(login):
    print("链接数据库")
    print(login)
    return "数据库连接结果"
@pytest.fixture()
def test01(login):
    print("用例1")
class Testcase():
    def test02(self,openbrowser):
        print("用例2")
    def test03(self,qingan):
        print("用例3")

我调用了conftest下的function跟session参数方法。

这里可以看到,都被调用了。当然方法不唯一,用法不唯一,这里做这么一个简单的介绍,主要看各位怎么个用法。module也可以这样写。

接下来我们来看看实际的示例,我打开浏览器:demo.py文件

from selenium import webdriver
# 这里每次都需要打开一次浏览器,然后关闭再打开
@pytest.fixture
def fox():
    fox1 = webdriver.Firefox()
    print("login")
    return fox1
def test_seacher(fox):
    fox.get("https://baidu.com")
    fox.quit()
def test_seacher1(fox):
    fox.find_element_by_id('kw').send_keys("pytest")
    fox.find_element_by_id('su').click()
    fox.quit()

这里是单独的fixture直接同一文件下调用。打开两开浏览器,有点像unittest中的setup用法。这里的test_seacher1`又再次打开了一次浏览器导致不是百度界面无法定位到元素。

那么我们看看session怎么用------conftest.py文件

import pytest
from selenium import webdriver
@pytest.fixture(scope='session')
def fox():
    fox = webdriver.Firefox()
    yield fox

demo.py文件

@pytest.mark.usefixtures('fox')
class TestCase():
    def test01(self,fox):
        fox.get("https://baidu.com")
        print(fox.title)
    def test02(self,fox):
        fox.find_element_by_id('kw').send_keys("pytest")
        fox.find_element_by_id('su').click()
    def test03(self,fox):
        fox.quit()

这里用到了mark标签中的usefixtures方法,不用解释应该也知道了有use的地方是什么意思了吧,使用fixture方法,这里直接引入了conftest中的fox,只打开一次浏览器就能往下定位了。是不是很神奇。当然,module也是用在conftest里面。


参数化

有点像数据驱动,可以处理一些测试数据,简单的看看它的一个格式情况:

argnames:参数名

       argvalues:参数对应值,类型必须为list

datas = [('qingan', '123'),('qingqingan', '123456')]
class TestQingan:
    @pytest.mark.parametrize(argnames=['username', 'password'], argvalues=datas)
    def testqing01(self, username, password):
        # 这里的运行两个用例
        print("处处把欢喜")
        print(username, password)

这里会把datas中的数据解析出来:列表中有几个元组就有几个对应的数据。

当然,还有一种情况就是会随机匹配对应的数值,说的比较抽象我们直接看看:

class TestQingan:   
    @pytest.mark.parametrize("username",["qingan","123456"])
    @pytest.mark.parametrize("password",["qingqingan","123456"])
    def testqing01(self, username, password):
        # 这里的运行两个用例
        print("处处把欢喜")
        print(username, password)

如果你这样写了,那么pytest会把username跟password中的列表打乱,然后一一匹配:


命名

不知道你是否喜欢pytest的命名规则,如果不喜欢,此处有一好办法,帮你解决。

跟目录下创建一个pytest.ini文件,在里面这样写。pytest会自动去识别。往下看会解释规则

[pytest]
addopts= -s -vv --alluredir=./result/xml
testpaths=../P_pytest/inidemo
python_files=test*.py
python_classes=Qing*
python_functions=qing*

以我上述的例子为例题运行出来的效果也与上述没有太大的差别,只是更改了名字而已:

class Qingan:
    @pytest.mark.parametrize("username",["qingan","123456"])
    @pytest.mark.parametrize("password",["qingqingan","123456"])
    def qing01(self, username, password):
        # 这里的运行两个用例
        print("处处把欢喜")
        print(username, password)

好了,下面解释一下pytest.ini里面的配置规则

[pytest]
addopts= -s -vv --alluredir=./result/xml
addopts= -s -vv --html=./report/test.html
# 这里是文件运行的目录../表示上级目录
# 这里是ALLURE测试报告数据存放的地方
addopts= -s -vv --alluredir=./result/xml
# 控制台运行输出报告        这里指定生成数据的地方   这里指定输出报告的地方
# allure generate --clean ./result/xml -o ./result/html   这里是在控制台输出的,可别搞混了
# 这里是寻找执行用例所存放的文件
testpaths=../P_pytest/inidemo
# 寻找执行用例。这里可更改用例名称,不在是test开头
python_files=test*.py
# 寻找对应的类运行
python_classes=Qing*
# 基于上述条件寻找对应的用例运行
python_functions=qing*

明白的安排上。前面将了一些allure测试报告的生成,怕你各位没看懂!

注意:pytest.ini中除了必须的配置参数外,不要存在其他的东西,汉字,字符,注释等。

扩展

既然生成了allure报告,为何不好好发挥一下呢,我们往报告里加入截图:

class Qingan:
    def qing02(self):
        fox = webdriver.Firefox()
        try:
            fox.get('https://baidu.com')
            time.sleep(3)
        except Exception as e:
            """点击错误的时候在报告中插入截图"""
            file_path = './img/' + str(int(time.time())) + ".png"
            fox.save_screenshot(file_path)
            with open(file_path, mode='rb') as file_img:
                f = file_img.read()
            # 此处的shouye是放在allure报告中的名字
            allure.attach(f, 'shouye', allure.attachment_type.PNG)
        fox.quit()

代码给到各位,仅限于借鉴参考!

目录
相关文章
|
1月前
|
Web App开发 IDE 测试技术
自动化测试的利器:Selenium 框架深度解析
【10月更文挑战第2天】在软件开发的海洋中,自动化测试犹如一艘救生艇,让质量保证的过程更加高效与精准。本文将深入探索Selenium这一强大的自动化测试框架,从其架构到实际应用,带领读者领略自动化测试的魅力和力量。通过直观的示例和清晰的步骤,我们将一起学习如何利用Selenium来提升软件测试的效率和覆盖率。
|
3月前
|
Web App开发 XML 测试技术
自动化测试框架设计:以Python和Selenium为例
【8月更文挑战第31天】在软件开发的快节奏中,自动化测试成为确保产品质量的关键步骤。本文将引导读者了解如何结合Python语言和Selenium工具来设计一个高效的自动化测试框架。通过浅显易懂的语言和实际代码示例,我们将探索自动化测试框架的核心组件,并学习如何实现它们。无论你是测试新手还是希望提升自动化技能的开发者,这篇文章都将为你打开一扇通向高效软件测试的大门。
|
3月前
|
IDE Java 测试技术
探索自动化测试框架:以Selenium为例
【8月更文挑战第27天】在软件开发的海洋中,自动化测试是那把能指引船只安全航行的灯塔。本文将带你走进自动化测试的世界,重点介绍如何使用Selenium这一流行的自动化测试工具,来构建强大的测试脚本。我们将一起学习如何安装和配置Selenium,编写基本的测试用例,以及如何处理测试中的等待和异常处理。通过这篇文章,你将能够掌握自动化测试的基本概念和技巧,为你的软件开发之旅增添一份保障。
|
3月前
|
Web App开发 IDE 测试技术
天呐!当揭开 Selenium 自动化测试框架的神秘面纱,设计与实现令人瞠目!
【8月更文挑战第12天】Selenium 是一强大自动化测试框架,用于Web应用测试。它含WebDriver、IDE和Grid等工具,支持Chrome、Firefox等浏览器。可通过编程模拟用户交互验证应用功能。例如使用Python结合Selenium WebDriver编写自动化测试脚本,实现打开网页、操作元素及断言等功能。还可结合测试框架和Selenium Grid提升测试效率和并行执行能力。
37 1
|
3月前
|
Web App开发 IDE 测试技术
自动化测试的利器:Selenium 框架深度解析
【8月更文挑战第31天】在软件开发的世界中,自动化测试是提高产品质量和开发效率不可或缺的一环。本文将深入探讨Selenium这一强大的自动化测试工具,从其架构、优势到实战应用,一步步揭示如何利用Selenium框架提升软件测试的效率和准确性。通过具体的代码示例,我们将展示Selenium如何简化测试流程,帮助开发者快速定位问题,确保软件的稳定性和可靠性。无论你是测试新手还是资深开发者,这篇文章都将为你打开一扇通往高效自动化测试的大门。
|
3月前
|
Web App开发 安全 测试技术
自动化测试中的Python魔法:使用Selenium和pytest框架
【8月更文挑战第31天】 在软件开发的海洋中,自动化测试是确保航行安全的灯塔。本文将带你探索如何利用Python语言结合Selenium和pytest框架,搭建一套高效的自动化测试体系。我们将从基础设置讲起,逐步深入到编写测试用例,最后通过一个实战案例来展示如何在实际项目中运用这些工具。文章旨在为读者提供一套清晰的自动化测试解决方案,让你的开发之旅更加顺畅。
|
3月前
|
前端开发 IDE 测试技术
自动化测试中的代码魔法:使用Python和Selenium框架
【8月更文挑战第31天】在软件开发的海洋中,自动化测试是一艘能够带领团队穿越波涛的帆船。本文将引导读者了解如何利用Python语言结合Selenium框架,编写简洁而强大的自动化测试脚本。我们将从搭建开发环境开始,逐步深入到实际案例,最后通过一个简单示例展示如何实现端到端的自动化测试流程。文章不仅提供实用的代码片段,还旨在激发读者对于软件测试深层次思考的热情。
|
3月前
|
Web App开发 测试技术 API
Web自动化测试框架(基础篇)--Selenium WebDriver工作原理和环境搭建
本文详细介绍了Selenium WebDriver的工作原理,包括其架构、通信机制及支持的浏览器,并指导读者如何在Python环境下搭建Selenium WebDriver的测试环境,从安装Python和Selenium库到编写并运行第一个自动化测试脚本。
221 0
|
4月前
|
测试技术 API Android开发
《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)
【7月更文挑战第15天】这是关于自动化测试框架中Selenium API二次封装的教程总结。教程中介绍了如何设计一个支持不同浏览器测试的页面基类(BasePage),该基类包含了对Selenium方法的二次封装,如元素的输入、点击、清除等常用操作,以减少重复代码。此外,页面基类还提供了获取页面标题和URL的方法。
107 2
|
4月前
|
存储 Web App开发 Java
《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)
【7月更文挑战第13天】这篇文章介绍了如何在Java中创建一个简单的自定义日志系统,以替代Log4j或logback。
294 5

热门文章

最新文章