I have a class that throws an exception when instantiated with wrong values and I would like to write a unit test raising an exception when given wrong parameters.
Instantiating an object outside of the self.assertRaises() doesn’t seem to cause any error and I fail to understand why it causes an error when I try to instantiate it within the assert
my class looks like this:
class Mark: def __init__(self, a, b, c): try: self.a = a self.b = int(b) self.c = int(c) except ValueError: print(e)
My test looks like this:
import unittest import main class Test(unittest.TestCase): def test_marks(self): self.assertRaises(ValueError, main.Mark("X", 5, 32)) self.assertRaises(ValueError, main.Mark(1, "X", 32)) self.assertRaises(ValueError, main.Mark(1, 5, "X")) if __name__ == "__main__": unittest.main()
But I get:
(base) ➜ Code Python3 test.py E ====================================================================== ERROR: test_marks (__main__.Test) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Code/test.py", line 12, in test_marks self.assertRaises(ValueError, main.Mark("X", 5, 32)) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/unittest/case.py", line 733, in assertRaises return context.handle('assertRaises', args, kwargs) File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/unittest/case.py", line 201, in handle callable_obj(*args, **kwargs) TypeError: 'Mark' object is not callable ---------------------------------------------------------------------- Ran 1 test in 0.001s FAILED (errors=1)
Do you know how should I do if I want to test this ?
Advertisement
Answer
The signature of assertRaises
is different than your usage. See the documentation Here
You should either provide it with a callable and the arguments it should call it with, or you should use the with
statement and call it as usual.
Here is a snippet, showing the two approaches:
def test_marks(self): self.assertRaises(ValueError, main.Mark, "X", 5, 32) with self.assertRaises(ValueError): main.Mark(1, "X", 32)
Based on your edited question: You actually don’t throw an exception, but catch it in your code, so the assertion fails, because you don’t do what you expect. Tests work!
Now, if you want to check if the exception was caught as expected, you should test if the print statement was printed:
import contextlib import io import unittest import main class Test(unittest.TestCase): def test_marks(self): with contextlib.redirect_stdout(io.StringIO()) as f: main.Mark(1, 2, 3) output = f.getvalue().strip() assert output == 'I am an exception' if __name__ == "__main__": unittest.main()
What we do here is to redirect the standard output to a simple text stream, then call your method, capture the output (stripping it to remove any unknown whitespaces) and check if the outputted string is the same as we expect it to be.
In my case, I just print "I am an exception"
. You should replace this with the output of your exception.