You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何为简易ATM程序的其余函数编写unittest单元测试

简易ATM程序unittest单元测试编写指南

首先先修正你现有代码和初版测试里的基础问题,否则测试无法正常运行:

  • 测试类存在语法错误:classTestATM要改为class TestATM(unittest.TestCase),注意父类TestCase为驼峰大写开头,类名和继承的父类之间要加空格
  • 业务代码里的user_pin、user_balance是全局变量,测试前需要预设固定值,避免测试结果受外部环境影响
  • 所有调用input()的交互函数不能直接运行测试,需要用unittest.mock模块的patch方法模拟用户输入,否则测试会卡住等待手动输入
  • 你写的初版PIN测试有逻辑错误:input()返回的输入值永远是字符串类型,传整数9876和字符串类型的存储PIN比对会永远返回False

1. 补全PIN校验函数测试

你目前只写了正确PIN的校验场景,需要补充错误PIN的反向用例:

import unittest
from unittest.mock import patch

# 先预设测试用的固定全局值
user_pin = "9876"
user_balance = 1000

# 这里放入你之前写的pin_validation、log_in、withdraw_cash业务函数

class TestATM(unittest.TestCase):
    def test_pin_validation_correct(self):
        # 正确PIN场景
        result = pin_validation("9876")
        self.assertTrue(result)
    
    def test_pin_validation_wrong(self):
        # 错误PIN场景
        result = pin_validation("1234")
        self.assertFalse(result)

2. 登录函数测试用例

登录逻辑需要覆盖3个核心场景,所有输入交互用patch模拟:

  • 首次输入正确PIN,直接登录成功
  • 前两次输错PIN,第三次输入正确,登录成功
  • 连续3次输错PIN,触发账户锁定异常
@patch('builtins.input', return_value="9876")
    def test_log_in_success_first_try(self, mock_input):
        result = log_in()
        self.assertTrue(result)
    
    @patch('builtins.input', side_effect=["1234", "5678", "9876"])
    def test_log_in_success_third_try(self, mock_input):
        result = log_in()
        self.assertTrue(result)
    
    @patch('builtins.input', side_effect=["1111", "2222", "3333"])
    def test_log_in_locked_after_3_wrong(self, mock_input):
        # 断言连续输错3次时抛出对应类型的异常,且错误信息匹配
        with self.assertRaises(TypeError) as e:
            log_in()
        self.assertEqual(str(e.exception), "Account locked")

3. 取款函数测试用例

取款逻辑需要覆盖2个核心场景,用setUp方法在每个用例执行前重置余额,避免不同测试之间的数据干扰:

  • 取款金额小于账户余额,取款成功,余额正确扣减
  • 取款金额大于账户余额,抛出余额不足异常
def setUp(self):
        # 每个测试用例执行前重置全局余额为初始值
        global user_balance
        user_balance = 1000

    @patch('builtins.input', return_value="200")
    def test_withdraw_success(self, mock_input):
        result = withdraw_cash()
        # 原函数取款成功返回False,断言返回值符合预期
        self.assertFalse(result)
        # 断言余额扣减正确
        global user_balance
        self.assertEqual(user_balance, 800)
    
    @patch('builtins.input', return_value="1200")
    def test_withdraw_insufficient_balance(self, mock_input):
        # 断言余额不足时抛出对应异常
        with self.assertRaises(ValueError) as e:
            withdraw_cash()
        self.assertEqual(str(e.exception), "Not enough funds in account")

*额外提示:你的业务代码里有两段永远不会执行的死代码,可以直接删掉:

  1. log_in函数里raise TypeError("Account locked")之后的return False
  2. withdraw_cash函数里return False之后的assert new_balance > 0,如果要保留这个余额为正的校验,需要把断言挪到return语句之前*

内容的提问来源于stack exchange,提问作者frenchtoast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:48:28