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

单元测试框架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,会显示详细的信息!如果在一个测试类中,单独执行某个测试用例,可以按照下图操作:

构建测试套件

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

分享到 :

发表评论

登录... 后才能评论