Python提高: unittest和 pytest的使用方法-由Deepseek产生

张开发
2026/6/8 2:39:04 15 分钟阅读
Python提高: unittest和 pytest的使用方法-由Deepseek产生
以下分别给出unittest和pytest的详细案例包含常见测试场景基本断言、异常测试、夹具、模拟、参数化、跳过/预期失败。1. 被测试代码 (待测模块calculator.py)# calculator.pyimportrequestsclassCalculator:defadd(self,a,b):returnabdefdivide(self,a,b):ifb0:raiseValueError(除数不能为零)returna/bdeffetch_data(url):模拟网络请求返回状态码和JSONresprequests.get(url)returnresp.status_code,resp.json()2. unittest 详细案例# test_unittest_demo.pyimportunittestfromunittest.mockimportpatch,MockfromcalculatorimportCalculator,fetch_dataclassTestCalculator(unittest.TestCase):基本测试 夹具 模拟 参数化 跳过classmethoddefsetUpClass(cls):所有测试运行前执行一次print(\n[setUpClass] 初始化计算器实例)cls.calcCalculator()classmethoddeftearDownClass(cls):所有测试运行后执行一次print([tearDownClass] 清理资源)defsetUp(self):每个测试方法前执行print(f\n[setUp] 准备测试:{self._testMethodName})deftearDown(self):每个测试方法后执行print(f[tearDown] 完成测试:{self._testMethodName})# ---------- 基本断言 ----------deftest_add_positive(self):self.assertEqual(self.calc.add(2,3),5)self.assertAlmostEqual(self.calc.add(0.1,0.2),0.3,places6)deftest_divide_normal(self):self.assertEqual(self.calc.divide(10,2),5.0)# ---------- 异常测试 ----------deftest_divide_by_zero(self):withself.assertRaises(ValueError)asctx:self.calc.divide(5,0)self.assertEqual(str(ctx.exception),除数不能为零)# ---------- 模拟 (mock) ----------patch(calculator.requests.get)deftest_fetch_data_success(self,mock_get):# 配置模拟对象mock_responseMock()mock_response.status_code200mock_response.json.return_value{key:value}mock_get.return_valuemock_response status,datafetch_data(http://example.com)self.assertEqual(status,200)self.assertEqual(data,{key:value})mock_get.assert_called_once_with(http://example.com)patch(calculator.requests.get)deftest_fetch_data_failure(self,mock_get):mock_responseMock()mock_response.status_code404mock_response.json.side_effectException(Not Found)mock_get.return_valuemock_responsewithself.assertRaises(Exception):fetch_data(http://example.com/bad)# ---------- 参数化测试 (使用 subTest) ----------deftest_add_multiple_inputs(self):test_cases[(1,2,3),(-1,-1,-2),(0,0,0),(100,-50,50)]fora,b,expectedintest_cases:withself.subTest(aa,bb,expectedexpected):self.assertEqual(self.calc.add(a,b),expected)# ---------- 跳过测试 ----------unittest.skip(演示跳过该功能尚未实现)deftest_multiply_not_implemented(self):passunittest.skipIf(True,条件满足时跳过)deftest_skip_conditionally(self):passunittest.expectedFailuredeftest_expected_failure(self):# 这个断言会失败但不会计入失败数self.assertEqual(1,2)if__name____main__:unittest.main(verbosity2)运行方式python test_unittest_demo.py或python -m unittest test_unittest_demo3. pytest 详细案例# test_pytest_demo.pyimportpytestfromunittest.mockimportMock,patchfromcalculatorimportCalculator,fetch_data# ---------- 夹具 (fixture) ----------pytest.fixture(scopeclass)defcalculator():类级别夹具返回计算器实例print(\n[fixture] 创建计算器实例)calcCalculator()yieldcalcprint([fixture] 销毁计算器实例)pytest.fixturedefsample_data():函数级别夹具返回测试数据return{a:10,b:5}# ---------- 测试类 ----------classTestCalculator:使用类级别夹具deftest_add(self,calculator,sample_data):resultcalculator.add(sample_data[a],sample_data[b])assertresult15# pytest 使用原生 assertdeftest_divide_normal(self,calculator):assertcalculator.divide(9,3)3.0deftest_divide_by_zero(self,calculator):withpytest.raises(ValueError,match除数不能为零):calculator.divide(5,0)# ---------- 参数化测试 (pytest 特色) ----------pytest.mark.parametrize(a,b,expected,[(1,2,3),(-1,-1,-2),(0,0,0),(100,-50,50),])deftest_add_parametrized(a,b,expected):calcCalculator()assertcalc.add(a,b)expected# 组合参数化 夹具pytest.mark.parametrize(input_val,expected,[(5,5),(0,0),(-3,-3)])deftest_identity(calculator,input_val,expected):assertcalculator.add(input_val,0)expected# ---------- 模拟 (使用 mocker fixture需要安装 pytest-mock) ----------# 也可以直接使用 unittest.mockpytest 自动兼容deftest_fetch_data_success(mocker):# 使用 pytest-mock 的 mocker fixturemock_getmocker.patch(calculator.requests.get)mock_responseMock()mock_response.status_code200mock_response.json.return_value{key:value}mock_get.return_valuemock_response status,datafetch_data(http://example.com)assertstatus200assertdata{key:value}mock_get.assert_called_once_with(http://example.com)deftest_fetch_data_failure():withpatch(calculator.requests.get)asmock_get:mock_responseMock()mock_response.status_code404mock_response.json.side_effectException(Not Found)mock_get.return_valuemock_responsewithpytest.raises(Exception):fetch_data(http://example.com/bad)# ---------- 跳过与预期失败 ----------pytest.mark.skip(reason演示跳过未实现功能)deftest_skip_example():passpytest.mark.skipif(True,reason条件满足时跳过)deftest_skip_conditionally():passpytest.mark.xfail(reason已知问题暂时预期失败)deftest_expected_failure():assert12# ---------- 临时文件与 capsys (pytest 内置 fixture) ----------deftest_capsys_example(capsys):print(Hello, world!)capturedcapsys.readouterr()assertcaptured.outHello, world!\ndeftest_tmp_path(tmp_path):dtmp_path/subd.mkdir()fd/test.txtf.write_text(pytest rocks)assertf.read_text()pytest rocks# ---------- 自定义标记 ----------pytest.mark.slowdeftest_slow_operation():importtime time.sleep(0.1)assertTrue# 运行方式: pytest -m slow (只运行标记为 slow 的测试)运行方式安装 pytestpip install pytest pytest-mock执行pytest test_pytest_demo.py -v带覆盖率pytest --covcalculator test_pytest_demo.py关键差异对比特性unittestpytest断言风格self.assertEqual(a, b)assert a b夹具setUp/tearDownpytest.fixture更灵活参数化subTest或parameterizedpytest.mark.parametrize模拟unittest.mockunittest.mock或mocker跳过/预期失败unittest.skip/expectedFailurepytest.mark.skip/xfail插件生态较少极丰富 (xdist, cov, asyncio…)学习曲线较低但代码冗长稍高但更简洁强大建议新项目直接选择pytest旧项目维护可使用 unittest。两者可混合使用pytest 能运行 unittest 风格的测试。

更多文章