Home > database >  TypeError: object is not callable when instantiating during unit test
TypeError: object is not callable when instantiating during unit test

Time:02-18

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 ?

CodePudding user response:

assertRaises() expects a callable and not a called function.

You just give the callable and append the arguments without ():

self.assertRaises(ValueError, main.Mark, "X", 5, 32)

Alternatively you can use a context manager:

with self.assertRaises(ValueError):
    main.Mark("X", 5, 32)

CodePudding user response:

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.

  • Related