Reputation: 5748
I'm trying to write a unit test that asserts that my nested custom exception is raised by a function.
The below sample code passes:
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()
However, when my raising code involves a try-except, my test fails:
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')
It returns the below error:
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)
I don't quite understand what arg 1 must be an exception type
means because I assume that my custom exception is an exception type.
Why is the second version with the try-except failing?
Upvotes: 1
Views: 2602
Reputation: 96172
The problem is that you've nested the definition of your exception class inside an enum:
class Weekdays(Enum):
MONDAY = 'mon'
TUESDAY = 'tue'
WEDNESDAY = 'wed'
THURSDAY = 'thu'
FRIDAY = 'fri'
class InvalidValue(Exception):
pass
enum's (through metaclass chicanery) make their class attributes singleton instances of the enum class, with the value you assigned to the attribute in the definition inside the .value
of that enum instance. Just like the other class attributes you defined in your enum. So, consider:
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
So, you could use:
with self.assertRaises(Weekdays.InvalidValue.value):
...
And in similarly, in parse
, you need:
raise Weekdays.InvalidValue.value() from e
But you are better off just defining InvalidValue
at the module level.
Upvotes: 1