单元测试框架unittest的介绍和简单使用

鳄鱼君

发表文章数:591

热门标签

, ,

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Python » 单元测试框架unittest的介绍和简单使用

unittest单元测试框架提供了创建测试应用实例、测试套件和批量执行测试用例的方案。

unittest简述

unittest属于标准库,也就是python自带的,不需要安装就可以直接使用!unittest 单元测试框架是对程序的最小模块进行的一种敏捷化测试

测试固件

假设现在要测试使用selenium打开百度首页搜索,呢么在测试之前需要打开浏览器并进入到百度,测试结束,需要关闭浏览器。测试固件提供了两种执行方式:

1.测试固件每次均执行

import unittest


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        print('start...')
        
    # 最后执行tearDown方法
    def tearDown(self) -> None:
        print('end...')
        
    # 再执行测试用例test_baidu方法
    def test_baidu(self):
        print('测试用例被执行')


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



start...
测试用例被执行
end...
test_baidu (__main__.BaiduTest) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

编写两个测试用例:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    def tearDown(self) -> None:
        self.driver.quit()

    # 再执行测试用例test_baidu方法
    def test_baidu_input(self):
        self.driver.find_element_by_id('kw').send_keys('鳄鱼君')

    def test_baidu_click(self):
        self.driver.find_element_by_id('su').click()


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

你会发现,两个测试用例,浏览器会被打开两次,关闭两次。测试用例很多,这样就非常不合理!
2.测试固件只执行一次

要想让测试用例至执行一次,就需要使用setUpClass和tearDownClass这两个测试固件,这样,不管有多少个测试用例,测试固件只执行一次,看代码:

import unittest


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    @classmethod
    def setUpClass(cls) -> None:
        print('start...')

    # 最后执行tearDown方法
    @classmethod
    def tearDownClass(cls) -> None:
        print('end...')

    # 再执行测试用例
    def test_1(self):
        print('测试用例被执行')

    def test_2(self):
        print('测试用例被执行')

    def test_3(self):
        print('测试用例被执行')


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




start...
测试用例被执行
测试用例被执行
测试用例被执行
end...
test_1 (__main__.BaiduTest) ... ok
test_2 (__main__.BaiduTest) ... ok
test_3 (__main__.BaiduTest) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

然后修改一下代码:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    driver = None

    @classmethod
    def setUpClass(cls) -> None:
        cls.driver = webdriver.Firefox()
        cls.driver.get('https://www.baidu.com')
        cls.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    @classmethod
    def tearDownClass(cls) -> None:
        cls.driver.quit()

    # 再执行测试用例
    def test_baidu_input(self):
        self.driver.find_element_by_id('kw').send_keys('鳄鱼君')

    def test_baidu_click(self):
        self.driver.find_element_by_id('su').click()


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

测试执行

代码运行的是unittest的main,我们看一下具体的源码:。你会发现verbosity的默认值是1。我们上面的代码是2,会显示详细的信息!如果在一个测试类中,单独执行某个测试用例,可以按照下图操作:

单元测试框架unittest的介绍和简单使用

构建测试套件

一个测试类中会有很多个测试用例,现在我想要让这些测试用例按照顺序执行。这里先打开百度搜索栏,然后输入内容,搜索:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    def tearDown(self) -> None:
        self.driver.quit()

    # 再执行测试用例test_baidu方法
    def test_baidu_input(self):
        self.driver.find_element_by_id('kw').send_keys('鳄鱼君')

    def test_baidu_click(self):
        self.driver.find_element_by_id('su').click()
        

if __name__ == '__main__':
    suite = unittest.TestSuite()
    # 先添加的先执行,后添加的后执行
    suite.addTest(BaiduTest('test_baidu_input'))  //先输入
    suite.addTest(BaiduTest('test_baidu_click'))  //再搜索
    unittest.TextTestRunner(verbosity=2).run(suite)

按照测试类执行:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    def tearDown(self) -> None:
        self.driver.quit()

    # 再执行测试用例test_baidu方法
    def test_baidu_input(self):
        self.driver.find_element_by_id('kw').send_keys('鳄鱼君')
        

    def test_baidu_click(self):
        self.driver.find_element_by_id('su').click()


if __name__ == '__main__':
    # 把测试用例类中所有的测试用例组成测试套件,比卖你注意向测试套件中添加测试用例
    suite = unittest.TestSuite(unittest.makeSuite(BaiduTest))
    unittest.TextTestRunner(verbosity=2).run(suite)

加载测试类,,最后会显示测试执行的时间:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    def tearDown(self) -> None:
        self.driver.quit()

    # 再执行测试用例test_baidu方法
    def test_baidu_input(self):
        self.driver.find_element_by_link_text('新闻').click()

    def test_baidu_click(self):
        self.driver.find_element_by_link_text('地图').click()


if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(BaiduTest)
    unittest.TextTestRunner(verbosity=2).run(suite)

按测试模块,执行该模块下的所有测试类。一个py文件就是一个模块,再一个py文件中,可以有N个测试类,N个测试用例,我们可以设置按照模块执行:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    def tearDown(self) -> None:
        self.driver.quit()

    # 再执行测试用例test_baidu方法
    def test_baidu_input(self):
        self.driver.find_element_by_link_text('新闻').click()

    def test_baidu_click(self):
        self.driver.find_element_by_link_text('地图').click()


if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromModule('test.py')
    unittest.TextTestRunner(verbosity=2).run(suite)

优化测试套件,单独把测试套件写成一个方法调用:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    # 先执行setUp方法
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    # 最后执行tearDown方法
    def tearDown(self) -> None:
        self.driver.quit()

    # 再执行测试用例test_baidu方法
    def test_baidu_input(self):
        self.driver.find_element_by_link_text('新闻').click()

    def test_baidu_click(self):
        self.driver.find_element_by_link_text('地图').click()

    @staticmethod
    def suite(test_class):
        suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
        return suite


if __name__ == '__main__':
    unittest.TextTestRunner(verbosity=2).run(BaiduTest.suite(BaiduTest))

分离测试固件

如果有多个测试类,呢么打开浏览器和关闭浏览器的代码都是重复的,我们可以将这些代码分离出去,然后每个测试类继承即可!

import unittest
from selenium import webdriver


class InitTest(unittest.TestCase):
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    def tearDown(self) -> None:
        self.driver.quit()

编写测试类的时候需要继承该类:

import unittest
from slave import InitTest


class BaiduTest(InitTest):

    def test_baidu_input(self):
        self.driver.find_element_by_link_text('新闻').click()

    def test_baidu_click(self):
        self.driver.find_element_by_link_text('地图').click()

    @staticmethod
    def suite(test_class):
        suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
        return suite


if __name__ == '__main__':
    unittest.TextTestRunner(verbosity=2).run(BaiduTest.suite(BaiduTest))

测试断言

判断实际测试结果与预期结果是否一致,一直通过,不一直报错。

方法 介绍
assertEqual(a,b) a == b
assertNotEqual(a,b) a != b
assertTrue(x) bool(x) is True
assertFalse(x) bool(x) is False
assertIs(a,b) a is b
assertIsNot(x) a is not b
assertIsNone(x) x is None
assertIsNotNone(x) x is not None
assertIn(a,b) a in b
assertNotIn(a,b) a not in b
assertIsInstance(a,b) isinstance(a,b)
assertNotIsInstance(a,b) not isinstance(a,b)

需要注意的是,在测试用例中不要进行if else判断,因为不是if,就是else,两者都会执行成功,而我们测试的结果,只有正确和错误,这样判断显然做测试就没有用处:

import unittest
from selenium import webdriver


class BaiduTest(unittest.TestCase):
    def setUp(self) -> None:
        self.driver = webdriver.Firefox()
        self.driver.get('https://www.baidu.com')
        self.driver.implicitly_wait(10)

    def tearDown(self) -> None:
        self.driver.quit()

    def test_baidu_input(self):
        title = self.driver.title
        if title == '百度':
             print('success')
        else:
            print('fail')


if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(BaiduTest)
    unittest.TextTestRunner(verbosity=2).run(suite)

结果是fail,但是测试时ok的,所以尽量要使用断言,来代替这样的判断!也不要再断言的位置捕获异常,异常捕获之后,测试还是ok的,测试毛线,就用断言

批量执行测试用例

现在再test文件下有test_baidu.py和test_eyujun.py两个文件,现在创建一个all_test.py文件用来批量执行这两个测试用例:

import os
import unittest


def all_case():
    # discover批量获取测试模块,start_dir测试路径,pattern正则匹配包名
    suite = unittest.TestLoader().discover(
        start_dir=os.path.dirname(__name__),
        pattern='test_*.py',
        top_level_dir=None
    )
    return suite


if __name__ == '__main__':
    unittest.TextTestRunner(verbosity=2).run(all_case())

你自己编写几个测试模块试一下,这里只给出批量执行的例子!

生成测试报告

这里可以借助第三方库生成HTML格式的测试报告,下载地址:https://github.com/tungwaiyip/HTMLTestRunner,下载 HTMLTestRunner.py文件后,把该文件放到 Python安装路径的Lib子文件夹中,例如,C:\Python36-32\Lib目录下。当然也可以使用pip命令:pip install html-testrunner

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《单元测试框架unittest的介绍和简单使用》 发布于2020-07-19

分享到:
赞(0) 赏杯咖啡

评论 抢沙发

9 + 4 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册