Python之Unittest

HTMLTestRunnerNew下载地址:
链接: https://pan.baidu.com/s/1p33EkYp73n2RcZlhXnnZsw 提取码: 7prr 复制这段内容后打开百度网盘手机App,操作更方便哦

前言

学习了好久的Python基础语法,今天,我们的学习内容终于要和测试挂钩了。学习自动化测试的第一步,我们首先接触的就是unittest。接下来,就让我们开始今天的学习内容。
首先,我们要知道的是,"unittest"是Python中一个自带的单元测试框架,使用的时候直接import导入就可以,而不需要去pip install。它里面封装好了一些校验返回的结果方法和一些用例执行前的初始化操作。

定义

在学习写代码之前,让我们学习一些有关的关键词定义。

TestCase

TestCase指的是一个测试用例,比如说,我们登陆中的“输入正确用户名和密码,登陆成功”,“输入正确用户名不输入密码,提示密码为空”,这些都是一个测试用例。

TestSuite

TestSuite 是一个测试用例的集合,就是将多个TestCase集合在一起就叫做TestSuit。在实战中,我们可以将所有一个模块的测试用例集合在一起,组成一个TestSuit。

TestLoader

TestLoader是用来加载TestCase到TestSuite中的,可以说是一种媒介吧。

TestRunner

TestRunner是来执行测试用例的,测试的结果会保存到TestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息

unittest代码解析

了解完各种定义,我们来看一下unittest的使用,看如下代码:

"""登陆模块代码"""
class Login:
    def __init__(self):
        self.name = None
        self.password = None

    def login(self, name, password):
        """
        登陆功能,当用户名和密码相等时登陆成功,否则登陆失败
        :param name: 用户名
        :param password: 密码
        """
        self.name = name
        self.password = password
        if self.name == self.password:
            print("登陆成功")
            return True
        else:
            print("登陆失败")
            return False

以上为我们的第一段代码,我们创建了一个Login类,Login类种有一个login函数,当输入的用户名和密码相等时,登陆成功,否则登陆失败。在此基础上,我们写一段测试代码如下:

import unittest


class UnitTestDemo(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        # 必须使用@classmethod 装饰器,所有test运行前运行一次
        super().setUpClass()
        print("setUpClass")

    @classmethod
    def tearDownClass(cls):
        # 必须使用@classmethod, 所有test运行完后运行一次
        super().tearDownClass()
        print("tearDownClass")

    def setUp(self):
        # 每个测试用例执行之后做操作
        self.login = Login()
        super().setUp()
        print("setUp")

    def tearDown(self):
        # 每个测试用例执行之前做操作
        super().tearDown()
        print("tearDown")

    def test_login_success(self):
        print("test_login_success")
        self.assertEqual(self.login.login("yoyo", "yoyo"), True)

    def test_login_fail(self):
        print("test_login_fail")
        self.assertEqual(self.login.login("youyou", "fail"), False)

我们一起来看一下UnitTestDemo这个自定义的单元测试类,首先我们在一开头就通过import导入了单元测试unittest模块,然后在定义UnitTestDemo类的时候,继承了unittest.TestCase,使得我们定义的类是一个单元测试类。这就是unittest最基本的用法,然后我们在UnitTestDemo类中,重写了四个方法,分别为“setUpClass”,“tearDownClass”,“setUp”和“tearDown”。

这四个函数,一看就是成对出现,setUpClass和tearDownClass是一对,setUp和tearDown是一对。首先我们来看第一对setUpClass和tearDownClass,这两个方法都是用“@classmethod 装饰器”进行装饰的,说明这是两个类方法,setUpClass方法是在所有测试用例执行前执行一遍,tearDownClass是在所有测试用例执行完后执行一遍。setUp方法和tearDown方法和前面两个类似,不同之处在于它们是两个实例方法,并且setUp方法在每一个测试用例之前都要执行一遍,tearDown方法在每一个测试用例后面都要执行一遍。那么我们就知道。我们运行一下上面的代码,如下图所示:
执行结果.png
如结果图所示,由于我们在测试代码种写了两个测试用例,分别为test_login_success和test_login_fail,所以我们的setup和tearDown方法各执行了两遍,两个类方法执行了一遍,执行顺序都是setUp开头的方法在tear开头的方法的前面。由此我们可以知道,如果我们想要写一些只运行一次的初始化代码,我们可以写在类方法里面,如果我们想要写一些测试用例相关的初始化代码可以写在setUp里面,在结束时,可以在tear开头的方法中进行关闭等处理。

接下来,让我们来看一下两个用例方法test_login_success和test_login_fail,在结果图中我们可以看出,虽然我们先定义了test_login_success方法,但是在执行的时候,却是test_login_fail方法先执行。这是为啥呢?原来,测试用例的执行顺序是根据ascii编码来定义先后的,这两个方法命名中,test_login_都一样但是fail中的f比success中的s在ascii编码中的顺序在前,所以先执行了test_login_fail方法,如果我们想要固定测试用例的执行顺序,我们可以在命名时加数字区分,如:


命名区分.png

如上图中的命名,中间添加数字,执行顺序就正过来了。这边还有一点需要注意的是,用例方法命名
都要以test开头!这一点很重要很重要,切记!!!

断言

在测试用例中,执行完测试用例后,最后一步是判断测试结果是pass还是fail,自动化测试脚本里面一般把这种生成测试结果的方法称为断言(assert)。下面,我就举例一些常用的断言

序号 断言方法 断言描述
1 assertEqual(arg1, arg2, msg=None) 验证arg1=arg2,不等则fail
2 assertNotEqual(arg1, arg2, msg=None) 验证arg1 != arg2, 相等则fail
3 assertTrue(expr, msg=None) 验证expr是true,如果为false,则fail
4 assertFalse(expr,msg=None) 验证expr是false,如果为true,则fail
5 assertIs(arg1, arg2, msg=None) 验证arg1、arg2是同一个对象,不是则fail
6 assertIsNot(arg1, arg2, msg=None) 验证arg1、arg2不是同一个对象,是则fail
7 assertIsNone(expr, msg=None) 验证expr是None,不是则fail
8 assertIsNotNone(expr, msg=None) 验证expr不是None,是则fail
9 assertIn(arg1, arg2, msg=None) 验证arg1是arg2的子串,不是则fail
10 assertNotIn(arg1, arg2, msg=None) 验证arg1不是arg2的子串,是则fail
11 assertIsInstance(obj, cls, msg=None) 验证obj是cls的实例,不是则fail
12 assertNotIsInstance(obj, cls, msg=None) 验证obj不是cls的实例,是则fail

在刚刚的代码中,我在登陆判断的时候用了assertEqual(),去判定结果是否和预期结果相等,这边不进行多余阐述,我们可以根据不同情况来调用上面不同的断言方法。

TestSuite三种用法

# 1.第一种suit方法
my_suit = unittest.TestSuite([UnitTestDemo("test_1_login_success"), UnitTestDemo("test_2_login_fail")])
# 2.第二种suit方法
my_suit = unittest.TestSuite()
my_suit.addTests([UnitTestDemo("test_1_login_success"), UnitTestDemo("test_2_login_fail")])
# 3.第三种suit方法
my_suit = unittest.TestSuite()
my_suit.addTest(UnitTestDemo("test_1_login_success"))
my_suit.addTest(UnitTestDemo("test_2_login_fail"))

以上这三种TestSuit的调用方法其实大同小异,都是将测试用例集合放入到TestSuit中,只是在写法中稍微不同,我们获取到my_suit之后,就可以进行调用了

with open(r"D:\\pycharmProject\\python_self_study\\files\\test15_report.txt", "w", encoding="utf-8") as f:
    runner = unittest.TextTestRunner(f)
    runner.run(my_suit)

我们获取到mySuit之后,首先新建并打开一个报告文件,这里就是test15_report.txt,然后创建一个TextTestRunner对象,并且run之前的my_suit,就可以执行我们放入到my_suit中的每一个测试用例啦。

那么,同学们难免有疑问,如果我有很多很多的测试用例要执行,难道我要一个个添加吗?哈哈!当然不是!!!,请看下面代码:

# 4.loader添加
loader = unittest.TestLoader()
tests = loader.loadTestsFromTestCase(UnitTestOne)
my_suit = unittest.TestSuite(tests)

我们的TestLoader作用更大,我们在实例中,可以将一个测试模块写成一个类并且继承unittest.TestCase,然后通过TestLoader的loadTestsFromTestCase方法一股脑添加,这样就不用一个一个手动添加了哈哈。是不是很带劲!!

HTMLTestRunner

写到这边,我们关于unittest模块的基础知识基本上就学完了,但是别慌,我们看一下,上面执行完之后的test15_report.txt中是啥东西。


test15_report

啊偶,尴尬,这个生成的测试报告也太简单了吧,简直没啥用。那么怎么生成好看易懂的测试报告呢?当然是要靠我们的HTMLTestRunner啦。这边我们先导入一个HTMLTestRunnerNew.py文件,此文件在文章最后给出,然后我们修改生成测试报告的代码如下:

with open(r"D:\\pycharmProject\\python_self_study\\files\\test15_report.html", "wb") as f:
    runner = HTMLTestRunnerNew.HTMLTestRunner(f, title=u'测试报告', description=u'用例执行情况:',tester="YoYo")
    runner.run(my_suit)

运行后生成一个类型为html的测试报告,我们打开看一下。如下图所示:


html类型测试报告.png

是不是详细很多呀?嘿嘿!

总结

到这里,我们unittest的基础知识就学习的差不多了,每个知识点都涉及到了,这里,我们要总结一下unittest编写测试用例的步骤:
1.编写测试用例TestCase
2.将测试用例塞入到TestSuit测试套件中
3.通过TestRunner运行测试套件中的所有测试用例
4.将执行完的结果放入到测试报告中‘
好啦,今天要讲的就这么多,打完收工!

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

推荐阅读更多精彩内容