首页 > 解决方案 > Python:当涉及 Try-Except 时,断言自定义异常被引发的单元测试失败

问题描述

我正在尝试编写一个单元测试,断言我的嵌套自定义异常是由函数引发的。

下面的示例代码通过:

from unittest import TestCase


class MyClass():
    class MyException(Exception):
        pass


def fail():
    raise MyClass.MyException()


class MyTests(TestCase):
    def test_throwsException(self):
        with self.assertRaises(MyClass.MyException):
            fail()

但是,当我的提升代码涉及 try-except 时,我的测试失败:

from unittest import TestCase
from enum import Enum


class Weekdays(Enum):
    MONDAY = 'mon'
    TUESDAY = 'tue'
    WEDNESDAY = 'wed'        
    THURSDAY = 'thu'        
    FRIDAY = 'fri'        

    class InvalidValue(Exception):
        pass


def parse(key: str) -> Weekdays:
    try:
        return Weekdays(key)
    except Exception as e:
        raise Weekdays.InvalidValue() from e


class MyTests(TestCase):
    def test_throwsException(self):
        with self.assertRaises(Weekdays.InvalidValue):
            parse('invalid')

它返回以下错误:

E
======================================================================
ERROR: test_throwsException (test_main.MyTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:\PythonCodes\playground\test_main.py", line 25, in test_throwsException
    with self.assertRaises(Weekdays.InvalidValue):
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 816, in assertRaises
    return context.handle('assertRaises', args, kwargs)
  File "C:\Users\Admin\AppData\Local\Programs\Python\Python38\lib\unittest\case.py", line 187, in handle
    raise TypeError('%s() arg 1 must be %s' %
TypeError: assertRaises() arg 1 must be an exception type or tuple of exception types

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

我不太明白什么arg 1 must be an exception type意思,因为我假设我的自定义异常异常类型。

为什么带有 try-except 的第二个版本失败了?

标签: pythonunit-testingexceptiontry-catch

解决方案


问题是您已将异常类的定义嵌套在枚举中:

class Weekdays(Enum):
    MONDAY = 'mon'
    TUESDAY = 'tue'
    WEDNESDAY = 'wed'        
    THURSDAY = 'thu'        
    FRIDAY = 'fri'        

    class InvalidValue(Exception):
        pass

枚举(通过元类诡计)使它们的类属性成为枚举类的单例实例.value,并使用您在该枚举实例内部的定义中分配给属性的值。就像您在枚举中定义的其他类属性一样。所以,考虑:

In [1]: from enum import Enum

In [2]:
   ...: class Weekdays(Enum):
   ...:     MONDAY = 'mon'
   ...:     TUESDAY = 'tue'
   ...:     WEDNESDAY = 'wed'
   ...:     THURSDAY = 'thu'
   ...:     FRIDAY = 'fri'
   ...:
   ...:     class InvalidValue(Exception):
   ...:         pass
   ...:

In [3]: Weekdays.MONDAY
Out[3]: <Weekdays.MONDAY: 'mon'>

In [4]: Weekdays.MONDAY.value
Out[4]: 'mon'

In [5]: Weekdays.InvalidValue
Out[5]: <Weekdays.InvalidValue: <class '__main__.Weekdays.InvalidValue'>>

In [6]: Weekdays.InvalidValue.value
Out[6]: __main__.Weekdays.InvalidValue

所以,你可以使用:

with self.assertRaises(Weekdays.InvalidValue.value):
    ...

同样,在 中parse,您需要:

raise Weekdays.InvalidValue.value() from e

但是你最好只InvalidValue在模块级别定义。


推荐阅读