Testing in Python – how can I use assertRaises in testing using 'unittest'?
Question:
I am trying to do a simple test in Python using ‘unittest‘, to see if a class throws an exception if it gets an unsuitable input for the constructor. The class looks like this:
class SummaryFormula:
def __init__( self, summaryFormula):
self.atoms = {}
for atom in re.finditer( "([A-Z][a-z]{0,2})(d*)", summaryFormula):
symbol = atom.group(1)
count = atom.group(2)
if pocet != "":
self.atoms[ symbol] = int(count)
else:
self.atoms[ symbol] = 1
My test is the following:
class ConstructorTestCase(unittest.TestCase):
def testEmptyString(self):
self.assertRaises(TypeError, ukol1.SummaryFormula(), "testtest")
if __name__ == '__main__':
unittest.main()
All I want is the test to fail, meaning that the exception of unsuitable input for constructor is not handled.
Instead, I get an error: __init__() takes exactly two arguments (1 given)
.
What am I missing? What is the second argument I should specify?
Also, what type of Error should I use to handle exception that an input not matchable by my regexp was passed to the constructor?
Answers:
That’s because your class requires a parameter while instantiating the object.
While you are passing
ukol1.SummaryFormula()
You should have been passing the parameter summaryFormula to it.
ukol1.SummaryFormula(someSummaryFormula)
Also the confusion is because your class name is SummaryFormula and the parameter that you pass to __init__
is also SummaryFormula
Or it should this be
self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")
assertRaises
is a little confusing, because you need to give it the callable, not an expression that makes the call.
Change your code to:
self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")
In your code, you are invoking the constructor yourself, and it raises an exception about not having enough arguments. Instead, you need to give assertRaises
the callable (ukol1.SummaryFormula), and the arguments to call it with (“testtest”). Then it can call it, catching and checking for exceptions.
A more-generic alternate format is
args=['testtest']
kwargs = {}
self.assertRaises(TypeError, ukol1.SummaryFormula, *args, **kwargs)
This is useful if your constructor is polymorphic and you want to loop over a list of different ways of miswriting the arguments, e.g.:
arg_lists = [
['testtest'],
['anothertest'],
['YAT'],
]
for args in arg_lists:
self.assertRaises(TypeError, ukol1.SummaryFormula, *args)
A more Pythonic way is to use with
command (added in Python 2.7):
with self.assertRaises(SomeException):
do_something()
Documentation: assertRaises
Since none of the other answers point on how you can use the context that encapsulates the code that causes the exception, here’s how you can do that.
with self.assertRaises(ValueError) as ctx:
<some code that throws an exception>
expected_msg = 'foo_bar_baz'
self.assertEquals(ctx.exception.message, expected_msg)
Attributes of interest in this unittest.case._AssertRaisesContext
, are:
- exception
- expected
- expected_regexp
- failureException
I am trying to do a simple test in Python using ‘unittest‘, to see if a class throws an exception if it gets an unsuitable input for the constructor. The class looks like this:
class SummaryFormula:
def __init__( self, summaryFormula):
self.atoms = {}
for atom in re.finditer( "([A-Z][a-z]{0,2})(d*)", summaryFormula):
symbol = atom.group(1)
count = atom.group(2)
if pocet != "":
self.atoms[ symbol] = int(count)
else:
self.atoms[ symbol] = 1
My test is the following:
class ConstructorTestCase(unittest.TestCase):
def testEmptyString(self):
self.assertRaises(TypeError, ukol1.SummaryFormula(), "testtest")
if __name__ == '__main__':
unittest.main()
All I want is the test to fail, meaning that the exception of unsuitable input for constructor is not handled.
Instead, I get an error: __init__() takes exactly two arguments (1 given)
.
What am I missing? What is the second argument I should specify?
Also, what type of Error should I use to handle exception that an input not matchable by my regexp was passed to the constructor?
That’s because your class requires a parameter while instantiating the object.
While you are passing
ukol1.SummaryFormula()
You should have been passing the parameter summaryFormula to it.
ukol1.SummaryFormula(someSummaryFormula)
Also the confusion is because your class name is SummaryFormula and the parameter that you pass to __init__
is also SummaryFormula
Or it should this be
self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")
assertRaises
is a little confusing, because you need to give it the callable, not an expression that makes the call.
Change your code to:
self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")
In your code, you are invoking the constructor yourself, and it raises an exception about not having enough arguments. Instead, you need to give assertRaises
the callable (ukol1.SummaryFormula), and the arguments to call it with (“testtest”). Then it can call it, catching and checking for exceptions.
A more-generic alternate format is
args=['testtest']
kwargs = {}
self.assertRaises(TypeError, ukol1.SummaryFormula, *args, **kwargs)
This is useful if your constructor is polymorphic and you want to loop over a list of different ways of miswriting the arguments, e.g.:
arg_lists = [
['testtest'],
['anothertest'],
['YAT'],
]
for args in arg_lists:
self.assertRaises(TypeError, ukol1.SummaryFormula, *args)
A more Pythonic way is to use with
command (added in Python 2.7):
with self.assertRaises(SomeException):
do_something()
Documentation: assertRaises
Since none of the other answers point on how you can use the context that encapsulates the code that causes the exception, here’s how you can do that.
with self.assertRaises(ValueError) as ctx:
<some code that throws an exception>
expected_msg = 'foo_bar_baz'
self.assertEquals(ctx.exception.message, expected_msg)
Attributes of interest in this unittest.case._AssertRaisesContext
, are:
- exception
- expected
- expected_regexp
- failureException