Python 单元测试框架unittest

单元测试框架unittest

一般习惯在根目录下新建tests文件夹专门放我们的测试,这个测试文件夹要把它变成一个package,也就是里面放一个__init__.py,方便导包

被测文件:

复制代码
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def add(self, other):
        return Vector(self.x + other.x,
                      self.y + other.y)

    def mul(self, factor):
        return Vector(self.x + factor,
                      self.y + factor)

    def dot(self, other):
        return self.x * other.x +\
               self.y * other.y

    def norm(self):
        return (self.x * self.x +
                self.y * self.y) ** 0.5
复制代码

找测试项规则

每一个测试文件必须要是test_开头test_*.py

创建的测试类,必须要继承 unittest 模块的 TestCase 类,即 unittest.TestCase

测试类习惯以Test开头或Test结尾

测试类里面的测试方法必须以test_开头

注意点:每个测试方法当它有一个地方fail的时候,它就不会继续往下运行了

断言方法

其他断言方法见:https://docs.python.org/zh-cn/3/library/unittest.html?highlight=unittest

 

单独说一下assertRaises,修改一下被测文件的__Init__方法

# 被测文件
class Vector:
    def __init__(self, x, y):  # x,y必须要是数
        if isinstance(x, (int,float)) and isinstance(y,(int,float)):
            self.x = x
            self.y = y
        else:
            raise ValueError('not a number')

测试__init__函数是不是成功的raise了这个ValueError,写法如下

class TestVector(unittest.TestCase):
    def test_init(self):
        v = Vector(1, 2)
        self.assertEqual(v.x, 1)
        self.assertEqual(v.y, 2)

        with self.assertRaises(ValueError):
            v = Vector('1', '2')  # 传了非数字,如果传入了数字那么就会fail

 

Test Fixture夹具

复制代码
import unittest

def setUpModule():
    print("模块级别开始动作")

def tearDownModule():
    print("模块级别结束动作")

class TestVector(unittest.TestCase):

    @classmethod    # 测试类级别一定要加@classmethod
    def setUpClass(cls):
        print("类级别开始动作")

    @classmethod
    def tearDownClass(cls):
        print("类级别结束动作")

    def setUp(self):
        print("测试方法级别开始动作")

    def tearDown(self):
        print("测试方法级别结束动作")

    def test_init(self):
        v = Vector(1, 2)
        self.assertEqual(v.x, 1)
        self.assertEqual(v.y, 2)
复制代码

跳过测试和预期失败

无条件地跳过装饰的测试,需要说明跳过测试的原因。

unittest.skip(reason) 

如果条件为真,则跳过装饰的测试。

unittest.skipIf(condition, reason) 

当条件为真时,执行装饰的测试

unittest.skipUnless(condition, reason)

不管执行结果是否失败,都将测试标记为失败。

unittest.expectedFailure()

测试用例

复制代码
import unittest

class TestVector(unittest.TestCase):

    @unittest.skip("直接跳过测试")
    def test_init(self):
        v = Vector(1, 2)
        self.assertEqual(v.x, 1)
        self.assertEqual(v.y, 2)

    # 这个测试不在window上运行
    @unittest.skipIf(sys.platform == 'win32', '不支持windows系统')
    def test_add(self):
        v1 = Vector(1, 2)
        v2 = Vector(2, 3)
        v3 = v1.add(v2)
        self.assertEqual(v3.x, 3)
复制代码

测试用例的执行顺序

多个测试目录 > 多个测试文件 > 多个测试类 > 多个测试方法(测试用例)

unittest默认根据ASCII码的顺序加载测试用例的(数字与字母的顺序为0~9,A~Z, a~z),所以 TestAdd 类会优先于 TestBdd 类被执行,test_aaa()方法会优先于 test_ccc()方法 被执行,也就是说,它不会按照测试用例的创建顺序从上到下执行的

除命名外,我们可以声明测试套件 TestSuite 类来控制测试用例的执行顺序,通过 addTest()方法按照一定的顺序来加载测试用例。

命令行执行测试

python -m unittest

python -m unittest tests.test_vector.TestVector.test_add

discover 方法

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。

复制代码
import unittest
# 定义测试用例的目录为当前目录中的 test_case/目录 test_dir = './test_case' suits = unittest.defaultTestLoader.discover(test_dir, pattern='test*.py')
if __name__ == '__main__': runner = unittest.TextTestRunner() runner.run(suits)
复制代码

discover()方法会自动根据测试用例目录(test_dir)查找测试用例文件(test*.py),并 将找到的测试用例添加到测试套件中

 

posted @   天才九少  阅读(23)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示