Is there a way to catch unittest exceptions with PyCharm?
Asked Answered
M

4

15

The python unittest runner handles all exceptions. I would like to catch them with my debugger.

Is there a way to make my unittest runner re-raise tests exceptions to terminate the process? I want to handle them myself.

Edit: Found a solution.

You can create a unittest.TestSuite and call debug() to run the tests you want to debug - including catching the exceptions with your debugger!

It can be easily done with this pattern:

import unittest

class DebuggableTestCase(unittest.TestCase):
    @classmethod
    def debugTestCase(cls):
        loader = unittest.defaultTestLoader
        testSuite = loader.loadTestsFromTestCase(cls)
        testSuite.debug()

class MyTestCase(DebuggableTestCase):
    def test_function_that_fails(self):
        raise Exception('test')

if __name__ == '__main__':
    MyTestCase.debugTestCase()
Monoplane answered 29/12, 2012 at 11:48 Comment(5)
That doesn't sound like how unit tests should be running, by their definition. I suppose this is to be able to figure out better what has happened when it has broken?Maddeu
This is to avoid re-running the test for debugging purposes.Monoplane
Then you are actively going against the pattern and purpose of unit tests.Maddeu
Then you are actively going against convenience. The purpose of unit tests is to: 1. Find out the things that don't work. 2. Help you fix the things that don't work. Look at my solution.Monoplane
@prgDevelop, adding your answer was very nice, but it would be better if you moved your answer from a question-edit to a proper answer below, you can answer your own questions. As an answer it can receive up votes and be counted among other existing answers. It would be easier to read this way.Upholster
I
8

I know this is an old thread, and perhaps some of these things weren't around when the question was asked. But just for posterity...

You can run your unittest tests with py.test as a test runner. You'll get some great features right out of the box. Directly to the point of your question, there are a few good ways to debug with py.test, including with PyCharm.

Specifically to debug on any failure, post-mortem, with PyCharm - what you are asking for - you can install the pytest-pycharm plugin.

pip install pytest-pycharm

(I am working in a virtualenv per-project so this has no downside for me. I recommend you do the same. Otherwise, be aware that you're installing it globally, and this plugin will be active for all projects using this Python interpeter.)

See also:

Insurance answered 24/6, 2016 at 20:45 Comment(0)
C
2

The solution added to question itself is not great IMO:

  1. It wouldn't work with PyCharm unittest runner, so you can debug it only as a script not as tests.
  2. It doesn't print information about testing progress and results.

My solution is more "hacky", but it doesn't have mentioned drawbacks. Also, test behavior changes only if tests are ran under debugger.

unittest.TestResult.addError is called in exception handler if an exception is not expected by the test. I redefine this method to re-raise exception being handled.

I use this class as a parent for my test cases:

class DebuggableTestCase(unittest.TestCase):
    def __add_error_replacement(self, _, err):
        value, traceback = err[1:]
        raise value.with_traceback(traceback)

    def run(self, result=None):
        if result and sys.gettrace() is not None:
            result.addError = self.__add_error_replacement
        super().run(result)

Solution was tested with Python 3.4 and PyCharm 3.4

Canoe answered 7/12, 2014 at 18:28 Comment(1)
Does not work with Python 2.7.10 and PyCharm 4.5.4 (after changing the call to ´super´). Is stops at the first failed test, but does not enter the debugger.Cummins
G
0

If what you want is inspect why the unittest failed, you don't really need to raise the Exception.

Just set a breakpoint at the line where the exception occurs and run under debug mode. PyCharm will drop to the debug screen and let you inspect variables and the call stack.

Gadmann answered 29/12, 2012 at 12:8 Comment(2)
That's the whole point, I don't want to run my unit tests twice. I managed to solve the issue on my computer with a patch. I modified unittest\case.py to re-raise my user exceptions if I use something like @unittest.onExceptionGoUnhandled for my TestCase. The decorator only defines a flag for the unittest runner. Works like charm :)Monoplane
Not as useful if you loop over items and one item throws something.Quart
P
0

Despite pytest-pycharm, there is also a somewhat hidden setting:

Settings | Build, Execution, Deployment | Python Debugger | Drop into debugger on failed tests

Also see PY-9848: Exception breakpoints to stop on failure in tests.

Plainspoken answered 26/7 at 20:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.