UnitTest
unittest是Python单元测试框架,类似于JUnit框架。
unittest中有4个重要的概念:test fixture, test case, test suite, test runner
Testcase:
一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码 (run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。
Test suite:
多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。
Test runner:
是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。
TestLoader:
是用来加载TestCase到TestSuite中的,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuite实例。
Test fixture:
对一个测试用例环境的搭建和销毁,是一个fixture,通过覆盖 TestCase的setUp()和tearDown()方法来实现。这个有什么用呢?比如说在这个测试用例中需要访问数据库,那么可以在setUp() 中建立数据库连接以及进行一些初始化,在tearDown()中清除在数据库中产生的数据,然后关闭连接。注意tearDown的过程很重要,要为以后的 TestCase留下一个干净的环境。关于fixture,还有一个专门的库函数叫做fixtures,功能更加强大。
使用unittest编写python的单元测试代码,包括如下几个步骤:
1、编写一个python类,继承 unittest模块中的TestCase类,这就是一个测试类
2、在上面编写的测试类中定义测试方法(这个就是指的测试用例),每个方法的方法名要求以 test 打头,没有额外的参数。 在该测试方法中 调用被测试代码,校验测试结果,TestCase类中提供了很多标准的校验方法,如 最常见的assertEqual。
3、执行 unittest.main() ,该函数会负责运行测试,它会实例化所有TestCase的子类,并运行其中所有以test打头的方法。
用法
1.用import unittest导入unittest模块
2.定义一个继承自unittest.TestCase的测试用例类,如class xxx(unittest.TestCase):
3.定义setUp和tearDown,这两个方法与junit相同,即如果定义了则会在每个测试case执行前先执行setUp方法,执行完毕后执行tearDown方法。
4.定义测试用例,名字以test开头,unittest会自动将test开头的方法放入测试用例集中。
5.一个测试用例应该只测试一个方面,测试目的和测试内容应很明确。主要是调用assertEqual、assertRaises等断言方法判断程序执行结果和预期值是否相符。
6.调用unittest.main()启动测试
7.如果测试未通过,则会显示e,并给出具体的错误(此处为程序问题导致)。如果测试失败则显示为f,测试通过为.,如有多个testcase,则结果依次显示。
代码
import unittest# class FirstTest(unittest.TestCase):
#
# def test_1(self):
# print("test_1")
#
# def test_2(self):
# print("test_2")
#
#
# if __name__ == '_main':
# unittest.main()#
# class NumbersTest(unittest.TestCase):
#
# def test_even(self):
# for i in range(0, 6):
# with self.subTest(i=i):
# self.assertEqual(i % 2, 0)# def setUpModule():
# createConnection()
#
# def tearDownModule():
# closeConnection()
#
# class Test(unittest.TestCase):
# @classmethod
# def setUpClass(cls):
# cls._connection = createExpensiveConnectionObject()
#
# @classmethod
# def tearDownClass(cls):
# cls._connection.destroy()from selenium import webdriver
import timeclass TestUnit1(unittest.TestCase):# 获取浏览器的驱动def setUp(self):# 1、self 就是类的引用/实例# 2、全局变量的定义:self.变量名self.driver = webdriver.Chrome()self.driver.maximize_window()self.url = "https://www.baidu.com"self.driver.get(self.url)time.sleep(3)# 在百度中搜索信息# 测试用例的命名: test_def test_search1(self):self.driver.find_element("id", "kw").send_keys("顾一野")self.driver.find_element("id", "su").click()time.sleep(6)def test_search2(self):self.driver.find_element("id", "kw").send_keys("account")self.driver.find_element("id", "su").click()time.sleep(6)# 关闭浏览器def tearDowm(self):self.driver.quit()# 一个入口if __name__ == "__main__":unittest.main()
import unittestclass TestCaseDemo(unittest.TestCase):def testassertdemo(self):self.assertIn(1, [1, 2, 3])self.assertNotIn(1, [2, 3, 4])self.assertEqual('1', '1')self.assertNotEqual(1, 2)self.assertTrue(2 == 2)def testassertdemo_1(self):self.assertDictEqual({"code": 1}, {"code": 1})self.assertListEqual([1, 2], [1, 2])self.assertMultiLineEqual("name", "name")def testassertdemo_2(self):self.assertGreater(2, 0)self.assertGreaterEqual(2, 0)self.assertNotRegex("1", "122") # 正则是否匹配self.assertCountEqual("12", "12")# 1、第一种方法,一条一条case加载用例
def suite():# 创建一个测试套件suite = unittest.TestSuite()# 将测试用例加载到测试套件中case1 = TestCaseDemo("testassertdemo")suite.addTest(case1)case2 = TestCaseDemo("testassertdemo_1")suite.addTest(case2)case3 = TestCaseDemo("testassertdemo_2")suite.addTest(case3)return suiteif __name__ == '__main__':runner = unittest.TextTestRunner()runner.run(suite())
unittest模块常用方法
assertEqual(a, b) a == bassertNotEqual(a, b) a != bassertTrue(x) bool(x) is TrueassertFalse(x) bool(x) is FalseassertIs(a, b) a is bassertIsNot(a, b) a is not bassertIsNone(x) x is NoneassertIsNotNone(x) x is not NoneassertIn(a, b) a in bassertNotIn(a, b) a not in bassertIsInstance(a, b) isinstance(a, b)assertNotIsInstance(a, b) not isinstance(a, b)
skip方法
有时候,测试用例很多,有些需要执行,有些不想执行,那就需要跳过一些测试用例,这时候就需要用到skip,skip用法:
无条件跳过,unittest.skip(“xxx”)
条件为True跳过,unittest.skipIf(1 < 2, ‘xxx’)
条件为False跳过,unittest.skipUnless(1 > 2, ‘xxx’)
执行失败不计入case总数中,unittest.expectedFailure
代码
import unittestclass Mytest1(unittest.TestCase):def setUp(self) -> None:print("===== setUp =====")def tearDown(self) -> None:print("===== tearDown =====")@classmethoddef setUpClass(cls) -> None:print("===== setUpClass =====")@classmethoddef tearDownClass(cls) -> None:print("===== tearDownClass =====")@unittest.skip("直接跳过")def test_1(self):print("test_1")@unittest.skipIf(1<2,"条件为True则跳过")def test_2(self):print("test_2")@unittest.skipUnless(1<2,"条件为False则跳过")def test_3(self):print("test_3")@unittest.expectedFailuredef test_4(self):print("test_4")self.assertEqual(4,5)if __name__ == "__main__":unittest.main()
生成HTML测试报告
from unittest import TestSuite
from HtmlTestRunner import HTMLTestRunnerclass Mytest1(unittest.TestCase):def test_1(self):print("test_1")def test_2(self):print("test_2")def test_3(self):print("test_3")def test_4(self):print("test_4")if __name__ == "__main__":# 创建一个测试套件 suitesuite = TestSuite()# 添加单个测试用例suite.addTest(Mytest1("test_3"))suite.addTest(Mytest1("test_1"))suite.addTest(Mytest1("test_2"))# 执行测试并输出html报告,output输出到xx目录下runner = HTMLTestRunner(output="result")runner.run(suite)
ddt模块
有时我们需要对大量的数据进行同一种逻辑函数测试,这时候可以用到ddt模块。
ddt,是一种 数据驱动测试 思想,数据和用例进行分离,通过外部数据去生成测试用例,可以快速的对大量数据和不同情况进行测试。
首先我们需要在python中安装ddt模块:pip install ddt。
数据引入的方式主要有以下几种:
@data装饰器的方式
json文件
yaml文件
其他
data装饰器
import unittest
from ddt import ddt, data, unpack# 先定义@ddt,用于表示要使用ddt了
@ddt
class Mytest1(unittest.TestCase):# data用于设定参数@data("a", "b", "c")def test_1(self, text):self.assertEqual("a", text)if __name__ == "__main__":unittest.main()
json文件
先编写json文件
[{"name": "test","age": 18},{"name": "test1","age": 20}
]
import unittest
from ddt import ddt, file_data@ddt
class Mytest1(unittest.TestCase):@file_data("/test.json")def test_1(self, **text):print(text)print(type(text))if __name__ == "__main__":unittest.main()
yaml文件
先编写yaml文件
# "-"表示一个列表-name: 'test1'age: 18-name: 'test2'age: 20
import unittest
from ddt import ddt, file_data@ddt
class Mytest1(unittest.TestCase):@file_data("/Users/tangliqi/Desktop/个人文档/json文件/test.yaml")def test_1(self, **text):print(text)print(type(text))if __name__ == "__main__":unittest.main()