目录

unittest介绍TestCase编写TestSuite与TextTestRunnerTestLoaderTestFixturesetUp和tearDownsetUpClass和tearDownClass

断言(重点)assertEqual(a, b) 和 assertNotEqual(a, b)assertTrue(x)和assertFalse(x)assertIn(a, b)和assertNotIn(a, b)

测试报告文件方式的测试报告HTML方式的测试报告

skip跳过用例

unittest介绍

unittest是Python自带的一个单元测试框架, 它可以做单元测试, 也能用于编写和运行重复的测试工作. 它给自动化测试用例开发和执行提供了丰富的断言方法, 判断测试用例是否通过, 并最终生成测试结果.

TestCase编写

TestCase指的就是测试用例测试类必须继承unittest.TestCase测试方法名称命名必须以test开头测试方法的执行顺序有Case序号决定, 并非由代码顺序决定

一个简单的例子:

# 1. 导入unittest

import unittest

# 2. 创建类继承unittest.TestCase

class Test(unittest.TestCase):

# 3. 创建测试用例方法, 方法要以test开头

# 执行顺序是根据case序号来的, 并非代码的顺序

def test_add_01(self):

print(3+2)

def test_add_02(self):

print(10+5)

TestSuite与TextTestRunner

在上面提到, 测试用例的执行顺序默认是由case序号决定的,但也可以使用TestSuite控制用例的执行顺序。

TestSuite(测试套件)可以组织多个测试用例TextTestRunner测试用例运行器

run()方法是测试用例的执行, 入参为suite测试套件

一个简单的例子

# 1. 导入unittest

import unittest

# 2. 创建类继承unittest.TestCase

class Test(unittest.TestCase):

# 3. 创建测试用例方法, 方法要以test开头

# 执行顺序是根据case序号来的, 并非代码的顺序

def test_add_01(self):

print(3+2)

def test_add_02(self):

print(10+5)

if __name__ == '__main__':

suite = unittest.TestSuite() # 实例化TestSuite

suite.addTest(Test("test_add_02")) # 添加测试用例

suite.addTest(Test("test_add_01"))

runner = unittest.TextTestRunner() # 实例化TextTestRunner

runner.run(suite) # 传入suite并执行测试用例

但是要注意, 如果在Pychram中直接右键运行, 它是不会执行main下面的内容, 需要修改pychram的运行方式 然后重新运行, 就会执行main下面的内容了.

重点,通常测试用例都是多个的,因此测试用例可以存放到列表中一次性添加到测试套件。这里可以使用suite.addTests()

case_list = ['Test("test_add_02")', Test("test_add_01")]

suite.addTests(case_list)

TestLoader

如果有多个测试文件时, 可以使用TestLoader加载测试用例

unittest.defaultTestLoader, 使用discover()去加载测试用例

找到指定目录下所有测试模块,并可递归查到子目录下的测试模块,只有匹配到文件名才能被加载 discover(start_dir, pattern=‘test*.py’, top_level_dir=None)

start_dir:要测试的模块名货测试用例目录pattern=“test*.py”: 表示用例文件名的匹配原则。 此处匹配文件名以“test”开头的“.py”类型的文件,*表示任意字符top_level_dir=None:测试模块的顶层目录, 如果没有顶层目录, 默认为None

一个小例子, 再目录下创建多个test开头的py文件, 并且写入测试方法 然后使用discover()方法读取测试用例并执行

import unittest

# dicsover方法查找用例

suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")

# 2.TextTestRunner运行用例

runer = unittest.TextTestRunner()

runer.run(suite)

TestFixture

setUp和tearDown

setUp()方法

主要是用来初始化测试环境, 它在每条测试用例执行前都会调用

tearDown()方法

主要作用是测试用例执行完毕后恢复测试环境, 即使出现异常也会调用此方法,每条用例执行结束后都会运行

一个简单的例子

import unittest

class Test(unittest.TestCase):

def setUp(self) -> None: # 调用setUp

super().setUp()

print("测试用例执行前操作")

def test_add_01(self):

print("num02")

def test_add_02(self):

print("num03")

def tearDown(self) -> None: # 调用tearDown

super().tearDown()

print("测试用例执行后操作")

# 返回结果

测试用例执行前操作

num02

测试用例执行后操作

测试用例执行前操作

num03

测试用例执行后操作

在上面的返回结果中可以明确的看出, 每条用例执行前都会先运行setUp,执行结束后都会运行tearDown

setUpClass和tearDownClass

setUpClass

初始化测试环境且只会执行一次。在类中需要加上@classmethod

tearDownClass

恢复测试环境且只会执行一次。在类中需要加上@classmethod

import unittest

class Test(unittest.TestCase):

@classmethod

def setUpClass(cls) -> None:

super().setUpClass()

print("测试前的操作")

@classmethod

def tearDownClass(cls) -> None:

super().tearDownClass()

print("测试后的操作")

def test_add_01(self):

print(3+2)

def test_add_02(self):

print(10+5)

# 返回结果

测试前的操作

15

5

测试后的操作

从返回结果可以看到setUpClass和tearDownClass都只是执行了一次,与setUp和tearDown的结果有很明显的区别。

注意,setUpClass和tearDownClass执行一次是针对当前的测试类而言的,如果当前的py文件有多个测试类, 那么它每个测试类都会执行一次。 如下:

# 1. 导入unittest

import unittest

# 2. 创建类继承unittest.TestCase

class Test(unittest.TestCase):

@classmethod

def setUpClass(cls) -> None:

super().setUpClass()

print("测试前的操作")

@classmethod

def tearDownClass(cls) -> None:

super().tearDownClass()

print("测试后的操作")

# 3. 创建测试用例方法, 方法要以test开头

# 执行顺序是根据case序号来的, 并非代码的顺序

def test_add_01(self):

print(3+2)

def test_add_02(self):

print(10+5)

class Test2(unittest.TestCase):

@classmethod

def setUpClass(cls) -> None:

super().setUpClass()

print("测试前的操作2")

@classmethod

def tearDownClass(cls) -> None:

super().tearDownClass()

print("测试后的操作2")

def test_add_03(self):

print(20)

def test_add_04(self):

print(40)

if __name__ == '__main__':

suite = unittest.TestSuite() # 实例化TestSuite

suite.addTests([Test("test_add_02"), Test("test_add_01"), Test2("test_add_03"), Test2("test_add_04")]) # 添加测试用例

runner = unittest.TextTestRunner() # 实例化TextTestRunner

runner.run(suite) # 传入suite并执行测试用例

断言(重点)

常用的断言

方法检查assertEqual(a, b)a == bassertNotEqual(a, b)a != bassertTrue(x)x的布尔值为真assertFalse(x)x的布尔值为假assertIn(a, b)a in bassertNotIn(a, b)a not in b

assertEqual(a, b) 和 assertNotEqual(a, b)

# 1. 导入unittest

import unittest

# 2. 创建类继承unittest.TestCase

class Test(unittest.TestCase):

def setUp(self) -> None:

super().setUp()

print("测试开始")

def test_add_01(self):

print("1 == 1")

self.assertEqual(1, 1) # 成功

def test_add_02(self):

print("1 == 2")

self.assertEqual(1, 2) # 失败

def test_add_03(self):

print("1 !=2 ")

self.assertNotEqual(1, 2) # 成功

def test_add_04(self):

print("1 != 1")

self.assertNotEqual(1, 1) # 失败

def tearDown(self) -> None:

super().tearDown()

print("测试结束")

assertTrue(x)和assertFalse(x)

class Test(unittest.TestCase):

@classmethod

def setUpClass(cls) -> None:

super().setUpClass()

print("测试前的操作2")

@classmethod

def tearDownClass(cls) -> None:

super().tearDownClass()

print("测试后的操作2")

def test_05(self):

self.assertTrue(1 < 2) # 成功

def test_06(self):

self.assertTrue(1 > 2) # 失败

def test_07(self):

self.assertFalse(1 > 2) # 成功

def test_08(self):

self.assertFalse(1 < 2) # 失败

assertIn(a, b)和assertNotIn(a, b)

import unittest

class Test(unittest.TestCase):

@classmethod

def setUpClass(cls) -> None:

super().setUpClass()

print("测试前的操作2")

@classmethod

def tearDownClass(cls) -> None:

super().tearDownClass()

print("测试后的操作2")

def test_09(self):

self.assertIn("a", "abc") # 成功

def test_10(self):

self.assertIn("a", "bcd") # 失败

def test_11(self):

self.assertNotIn("a", "bcd") # 成功

def test_12(self):

self.assertNotIn("a", "abc") # 失败

测试报告

文件方式的测试报告

import unittest

# dicsover方法查找用例

suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")

# 打开文件对象

with open("test_report.txt", "a") as f:

# TextTestRunner运行用例

runer = unittest.TextTestRunner(stream=f, verbosity=2) # verbosity=2 输出详细日志

runer.run(suite)

HTML方式的测试报告

HTML报告需要导入HTMLTestRunner.py,这个文件原本只支持python2,python3需要修改部分代码才能使用。 然后我发现CSDN这里已经有人上传过这个资源了, 不过貌似要收费, 我这里也传一个网盘吧, 这是已经修改好支持python的, 直接使用就行。

链接:https://pan.baidu.com/s/171jiRp9lw8Gtrl140g0uJw

提取码:64db

回到正题,HTMLTestRunner的用法其实和TextTestRunner的差不多, 代码如下:

import unittest

from lib.HTMLTestRunner import HTMLTestRunner

# dicsover方法查找用例

suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")

with open("test_report.html", "wb") as report:

runner = HTMLTestRunner(stream=report, verbosity=2, title="HTML测试报告", description="这是练习的测试报告")

runner.run(suite)

运行结束后在本地就会看到多了一个HTML文件,打开就能看到测试报告了

skip跳过用例

在遇到不想执行的测试用例时,可以使用skip方法

@unittest.skip(reason) :无条件跳过用例, reason是说明原因@unittest.skipIf(condition, reason):condition为true时跳过用例@ unittest.skipUnless(condition, reason):condition为False的时候跳过

实例代码:

# 1. 导入unittest

import unittest

class Test(unittest.TestCase):

@classmethod

def setUpClass(cls) -> None:

super().setUpClass()

print("测试前的操作2")

@classmethod

def tearDownClass(cls) -> None:

super().tearDownClass()

print("测试后的操作2")

@unittest.skip("无条件跳过")

def test_09(self):

self.assertIn("a", "abc")

@unittest.skipIf(2>1, "因为2>1所以跳过")

def test_10(self):

self.assertIn("a", "bcd")

@unittest.skipUnless(1>2, "因为1>2为假,所以跳过")

def test_11(self):

self.assertNotIn("a", "bcd")

def test_12(self):

self.assertNotIn("a", "abc")

然后执行用例并生成测试报告

import unittest

from lib.HTMLTestRunner import HTMLTestRunner

# dicsover方法查找用例

suite = unittest.defaultTestLoader.discover("unittest_test", "test*.py")

with open("test_report.html", "wb") as report:

runner = HTMLTestRunner(stream=report, verbosity=2, title="HTML测试报告", description="这是练习的测试报告")

runner.run(suite)

测试报告,只剩下了一个测试用例了