Python unittest重写__init__实例化类报参数数量错误排查
实践简单测试驱动开发过程中,基于Python unittest框架编写多场景测试用例验证计算器程序逻辑,尝试通过重写测试类的__init__方法实例化被测Calculator类时,执行测试命令抛出报错,开发工具为Visual Studio Code,要求保留__init__方法实现实例化逻辑。
测试文件 Calculator_tests.py
import unittest import Calculator_steps as CalculatorClass class TestCalculator(unittest.TestCase): def __init__(self): self.calculator = CalculatorClass.Calculator() # 实例化被测Calculator类 def test_DecimalValues(self): with self.assertRaises(Exception): self.calculator.addNumbers('3.55,8.76') def test_NonNumeric(self): with self.assertRaises(Exception): self.calculator.addNumbers('7,8,e') def test_MoreThanThreeIntegers(self): with self.assertRaises(Exception): self.calculator.addNumbers('5,7,2,8') def test_MoreThan100(self): with self.assertRaises(Exception): self.calculator.addNumbers('109,76,90')
被测逻辑文件 Calculator_steps.py
class Calculator: def addNumbers(self, numberlist): total = 0 if numberlist=="": numberlist ="0" numbers = numberlist.split(",") if len(numbers)>3: raise TypeError("Only three values can be entered") for i in range(len(numbers)): if int(numbers[i])>100: raise TypeError("Only values less than 100 is allowed") try: total = total +int(numbers[i]) except ValueError: TypeError("Only integers can be entered") return total
执行报错信息
执行命令py -m unittest Calculator_tests.py后抛出核心错误:
TypeError: TestCalculator.__init__() takes 1 positional argument but 2 were given
完整报错栈:
PS C:\Users\mudit> py -m unittest Calculator_tests.py Traceback (most recent call last): File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code exec(code, run_globals) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\__main__.py", line 18, in <module> main(module=None) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\main.py", line 100, in __init__ self.parseArgs(argv) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\main.py", line 147, in parseArgs self.createTests() File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\main.py", line 158, in createTests self.test = self.testLoader.loadTestsFromNames(self.testNames, File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\loader.py", line 220, in loadTestsFromNames suites = [self.loadTestsFromName(name, module) for name in names] File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\loader.py", line 220, in <listcomp> suites = [self.loadTestsFromName(name, module) for name in names] File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\loader.py", line 191, in loadTestsFromName return self.loadTestsFromModule(obj) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\loader.py", line 124, in loadTestsFromModule tests.append(self.loadTestsFromTestCase(obj)) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\loader.py", line 93, in loadTestsFromTestCase loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\suite.py", line 24, in __init__ self.addTests(tests) File "C:\Users\mudit\AppData\Local\Programs\Python\Python310\lib\unittest\suite.py", line 57, in addTests for test in tests: TypeError: TestCalculator.__init__() takes 1 positional argument but 2 were given
unittest框架加载测试用例时,会为每个测试方法单独实例化一次测试类,实例化时自动传入当前待执行的测试方法名作为入参。重写的__init__方法仅定义了self参数,既未匹配父类构造方法的参数签名,也未调用父类初始化逻辑,参数传入时数量不匹配,直接抛出类型错误。
保留__init__实例化的修复方式
如果必须通过__init__方法完成被测类实例化,需要修改__init__方法的参数签名,接收框架传入的方法名参数,同时通过super()调用父类unittest.TestCase的构造方法完成基础初始化,修改后的__init__代码如下:
def __init__(self, methodName='runTest'): super().__init__(methodName) self.calculator = CalculatorClass.Calculator() # 实例化被测Calculator类
被测代码额外bug修复
修改完构造方法后测试仍会存在失败场景,原因是Calculator_steps.py中捕获非数字输入的ValueError时,仅创建了TypeError对象但没有使用raise抛出,需要修改对应代码:
try: total = total +int(numbers[i]) except ValueError: # 补充raise关键字抛出异常 raise TypeError("Only integers can be entered")
框架推荐写法(更稳妥)
unittest框架原生提供了setUp()实例方法,会在每个测试方法执行前自动运行,专门用于测试前置资源初始化,不需要重写构造方法,还能保证每个测试方法使用全新的被测对象实例,避免测试用例之间的状态污染,写法如下:
class TestCalculator(unittest.TestCase): def setUp(self): self.calculator = CalculatorClass.Calculator() # 其余测试方法保持不变
内容的提问来源于stack exchange,提问作者JMB

