自动化测试入门(unittest和pytest)

在我们真正的编写测试用例之前,我们需要了解一下测试框架。目前python自带的unittest和第三方测试框架pytest这两个测试框架比较流行,unittest在过去使用的人很多,近两年pytest有逐渐取代unittest之势。今天我们先了解一下这两个测试框架。

unittest

认识unittest

在我们真正的编写测试用例之前,我们需要了解一下测试框架。
unittest是python自带的单元测试框架,尽管其主要是为单元测试服务的,但我们也可以用它来做自动化测试。
unittest框架为我们编写用例提供了如下的能力:
定义用例的能力。unittest框架有一套固有套路,可以让我们定义测试用例时更加简单和统一
断言的能力。unittest框架提供了一系列的断言
各种执行策略。通过test suit或者扩展的方式,我们可以自定义用例执行的策略

用例编写

我们先说一下用例的格式吧,我们先写个测试用例吧:

import unittest
class PrintTest(unittest.TestCase):
    def setUp(self):
        self.num = 3
        print("num0:%s"%self.num)

    def test_test1(self):
        self.num= self.num+3
        print("num1:%s"%(self.num))
        self.assertEqual(self.num,6,"self.num发生改变不等于3")

    def test_test2(self):
        print("num2:%s"%self.num)

    def tearDown(self):
        self.num = 0
        print("num3:%s"%self.num)
        
        
if __name__ == '__main__':
    unittest.main()

接下来由这个例子给大家讲一下unittest如何编写测试用例
导入unittest包

import unittest

这个就不用我多说了吧,python语言需要用哪个包或者模块时候一定要先导入才能使用
定义测试类

class PrintTest(unittest.TestCase)

初学者看到这一行就害怕,其实大可不必。暂且把它当作是一个套路吧,测试类的名字你可以随意取,当然了最好遵循python的PEP8规范,这样代码看起来更加整洁美观。所有的测试类都必须直接或间接的继承自unittest.TestCase类。总之,这还是套路,记住就好。
用例初始化数据

    def setUp(self):
        self.num = 3
        print("num0:%s"%self.num)

setUp(self)方法是一个测试用例初始化方法,在每个测试用例执行之前都会执行一次,是做数据初始化的好地方。在上面的例子里,我们为每一个测试方法都定义了被测对象--self.num,通俗一点就是每次执行测试用例时,self.num都会被赋值为3
测试用例

    def test_test1(self):
        self.num= self.num+3
        print("num1:%s"%(self.num))
        self.assertEqual(self.num,3,"self.num发生改变不等于3")

首先,在unittest测试框中,他会把以test开头的函数做位测试用例,换句话说,就是每个测试用例的命名已经做了约束,开头必须是test,只有test开头的才是测试用例
另外,unittest框架自身也有断言,断言是测试用例的一个重要组成部分,断言的设置直接决定着自动化测试用例的效果。这里强调一下,大家一定要养成在断言后加入自己业务相关的信息,方便根据自动化报告分析错误,可以提高发现问题的效率
测试环境恢复

    def tearDown(self):
       self.num = 0
       print("num3:%s"%self.num)

在测试过程中,是需要对测试后的环境和数据进行恢复的,在unittest测试框架中,tearDown(self)这个方法就是用来恢复测试环境的,每个用例执行完都会执行一遍
这里我在补充一点,如果是测试环境需要初始化和恢复,而且不需要每个测试用例都初始化,我们可以用setUpClass()和tearDownClass()这两个类,但是必须使用@classmethod装饰器进行修饰

@classmethod
setUpClass()
    self.num=0

这样表示在当前类里所有测试用例执行之前将self.num赋值为0,在用例执行过程中不再执行,适用于初始化测试环境

@classmethod
tearDownClass()
    self.num=0

这样表示在当前类里所有测试用例执行完之后将self.num恢复为0,在单个用例执行结束后不再执行,适用于恢复测试环境,这里我强调一下这两个类作用域仅限于当前类里的所有test,不是所有的测试用例py文件
用例执行

if __name__ == '__main__':
   unittest.main()

依然是套路,上面的代码表示,如果直接执行该python文件的话,就运行所有的测试类里的测试用例,也就是运行所有的以test开头的方法,我们姑且这么认为,unittest.main()是最简单的用例执行方法
接下来我们将上述代码运行一遍看看结果

num0:3
num1:6
num3:0

num0:3
num2:3
num3:0

Ran 2 tests in 0.000s
OK

从结果我们可以看到,每个测试用例执行顺序是setUp-->test_case-->tearDown

unittest小结

使用unittest的话需要记住下面的几点
导入unittest
定义继承自unittest.TestCase的测试类
定义以test开头的测试方法,这个方法就是测试用例,你可以在一个类里定义n个测试用例
断言后面的信息尽量和自己业务相关,方便定位问题
unittest.main()是执行测试用例最简单的方式

pytest

更完善的pytest

近两年pytest使用的人也越来越多,主要是pytest的扩展性和其他方面的功能要比unittest更完善,最最重要的是,pytest可以兼容unittest,也就是说unittest的测试用例在pytest框架里也能执行,但是要注意的一点是文件名要符合pytest的规则。

pytest用例编写

我们首先说一下pytest的用例编写规则:
测试文件以test_开头(以test结尾也可以)
测试类以Test开头,并且不能带有 init 方法
测试函数以test
开头
断言还是继承python的断言assert
现在我们参照这个规则把上面的unittest框架的测试用例用pytest实现
test_print.py

import pytest
class TestPrint:
    def setup(self):
        self.num = 3
        print("num0:%s"%self.num)

    def test_test1(self):
        self.num= self.num+3
        print("num1:%s"%(self.num))
        assert self.num==6,"self.num发生改变不等于6"

    def test_test2(self):
        print("num2:%s"%self.num)

    def teardown(self):
        self.num = 0
        print("num3:%s"%self.num)


if __name__ == '__main__':
    pytest.main(['-s', 'test_print.py'])

定义测试类

class TestPrint:

测试类一定要以Test开头,记住,还是套路,小写test或者Test放在类名后面都不行,会加载不到里面的测试用例
测试环境数据初始化与恢复
pytest里面依然是使用setup()和teardown()作为初始化数据和恢复测试环境的方法,只不过是全小写了而已。当然在pytest也存在setup_class()和
teardown_class()这样的类,用来在当前测试类里所有测试用例执行之前初始化和全部执行完后恢复数据和环境,且不需要再使用@classmethod这样的装饰器进行修饰
测试用例执行
pytest在执行测试用例时可以参数化,而且根据不同的需要可以定制化执行结果,我们先简单看几个参数:

    pytest.main(['-s', 'test_print.py'])

#output:
collected 2 items

test_print.py num0:3
num1:6
.num3:0
num0:3
num2:3
.num3:0
============================== 2 passed in 0.08s ==============================

可以把print的内容打印出来,并输出执行结果和用时

    pytest.main(['-v', 'test_print.py'])

#output:
collecting ... collected 2 items

test_print.py::TestPrint::test_test1 PASSED                              [ 50%]
test_print.py::TestPrint::test_test2 PASSED                              [100%]

============================== 2 passed in 0.09s ==============================

这里是不是没有print的内容了,他会展示每条case的执行结果
当然我们还可以组合使用

    pytest.main(['-v','-s', 'test_print.py'])

#output:
collecting ... collected 2 items
test_print.py::TestPrint::test_test1 num0:3
num1:6
PASSEDnum3:0
test_print.py::TestPrint::test_test2 num0:3
num2:3
PASSEDnum3:0
============================== 2 passed in 0.06s ==============================

既可以显示print内容还可以看到每条用例的执行结果
常用命令参数

命令行 解释
pytest --version 显示版本信息
pytest --fixtures 显示可用的内置函数
pytest -h --help 显示参数和配置的帮助信息
pytest --lf 运行上一次运行失败的用例
pytest -x --exitfirst 第一次失败后停止
pytest --maxfail=2 第二(n)次失败后停止
pytest test_mod.py 运行单个文件中的用例
pytest testcase/ 运行文件夹下的用例
pytest -k "MyClass and not method" 关键字表达式(文件名、类名、方法名)运行测试用例
(将运行TestMyClass.test_something 不运行TestMyClass.test_method_simple)
pytest test_mod.py::test_func 运行模块内特指的方法
pytest test_mod.py::TestClass::test_method 运行模块下类内特指的方法
pytest -m slow marker运行测试用例(运行所有被装饰器标记@pytest.mark.slow的用例)
pytest --pyargs pkg.testing 从包中运行测试用例(这将要导入import pkg.testing)
pytest -ra 运行测试用例(显示测试总的结果信息,输出信息的最后)
pytest -rp 运行测试用例(显E示测试通过的结果信息,输出信息的最后)
pytest -rE 运行测试用例(显示测试错误的结果信息,输出信息的最后)
pytest -rs 运行测试用例(显示测试跳过的结果信息,输出信息的最后),也可以结合使用 -rfs – 显示跳过、失败的
pytest -v pytest1.py 用于显示每个测试函数的执行结果
pytest -q pytest1.py 只显示整体测试结果
pytest -s pytest1.py 用于显示测试函数中print()函数输出
pytest --durations=10 获得最慢的10个测试持续时间表
pytest --junitxml=path 生成一个结果集xml文件,可用于Jenkins 持续集成
pytest --pastebin=failed 为每个失败的用例创建一个URL

pytest小结

关于pytest的使用方法我就先介绍这么多了,关于pytest的其他更高阶的用法,大家可以去查阅pytest使用手册

unittes VS pytest

用例编写

使用unittest编写测试用例必须遵循以下规则:

1.测试类必须要继承 unittest.TestCase

2.测试方法必须以test_kai开头

pyest是Python的第三方测试框架,是基于unittest的扩展框架,比unittest更简洁高效,使用pytest编写测试用例必须遵循以下规则:

1.测试文件必须以test开头或者_test结尾

2.测试方法需以test开头

3.测试类必须以Test开头

前置跟后置

1.unittest提供了setUp/tearDown,每个用例运行前、结束后运行一次。setUpClass和tearDownClass,用例执行前、结束后,只运行一次。
2.pyets 可以在函数前使用@pytest.fixture()装饰器,fixture使用范围可以是:function(函数级别)、class、module(模块级别)、package(包级别)、session(多个测试类可以共用一个session)

优势

1.fixure命名更加灵活,局限性比较小
2.conftest.py 配置里可以实现数据共享,不需要import就能自动找到一些配置,可供多个py文件调用。
3.scope="session" 以实现多个.py跨文件使用一个session来完成多个用例

断言

1.unittest提供了assertEqual、assertIn、assertTrue、assertFalse等

2.pytest直接在assert 后面接表达式

失败重跑

1.unittest无此功能

2.pytest支持

参数化

1.unittest需要依赖于ddt库

2.pytest直接使用@pytest.mark.parametrize装饰器

扩展性

与unittest相比,pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-xdist(多CPU分发)等

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容