Use TestCase.assertRaises from the unittest module, for example:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
Answer from Moe on Stack OverflowUse TestCase.assertRaises from the unittest module, for example:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
Since Python 2.7 you can use context manager to get ahold of the actual Exception object thrown:
import unittest
def broken_function():
raise Exception('This is broken')
class MyTestCase(unittest.TestCase):
def test(self):
with self.assertRaises(Exception) as context:
broken_function()
self.assertTrue('This is broken' in context.exception)
if __name__ == '__main__':
unittest.main()
assertRaises
In Python 3.5, you have to wrap context.exception in str, otherwise you'll get a TypeError
self.assertTrue('This is broken' in str(context.exception))
python - In Python3, how do you test exception handling within a unit test? - Stack Overflow
python - What is the difference between unit testing and handling exceptions - Software Engineering Stack Exchange
Python unittest an error-handling function
Unit Test for Expected Exception in Python - Ask a Question - TestMu AI (formerly LambdaTest) Community
If you're using pytest there's functionality for that...
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
https://docs.pytest.org/en/latest/assert.html#assertions-about-expected-exceptions
If your class (that defines the test_auth_failure method) extends unittest.TestCase, you should use [Python.Docs]: unittest - assertRaises(exception, callable, *args, **kwds):
Replace your try / except clause by:
with self.assertRaises(exceptions.HTTPUnauthorized):
self.api.auth()
or
self.assertRaises(exceptions.HTTPUnauthorized, self.api.auth)
Let's look at your get_turn method:
def get_turn(self):
try:
assert self.turn >= 0
except ValueError:
print('turn number must be positive')
There are a couple problems here:
- In most languages, assertions only execute in debug mode. If you run Python with the
-Oflag, your assertion will never execute! - A failed assertion will raise an
AssertionError, not aValueError - This should not have been allowed to be in an invalid state in the first place. If
self.turnis negative, then the actual bug happened somewhere else.
Here's how I would rewrite it:
def set_turn(self, turn):
if turn < 0:
raise ValueError('Turn number must be nonnegative')
self.turn = int(turn)
def get_turn(self):
assert self.turn >= 0 # This should never fail. If it does, you made a programming mistake.
return self.turn
And then in your unit tests, you could write calls to make sure they behave as expected.
Exception handling and unit testing solve different problems:
- Exception Handling: Allows a running program to recover from an exceptional condition (like expecting to be able to open a file but it is open in another program).
- Unit Tests: Tests the behavior of small parts (units) of your program to make sure they behave the way you expect.
Exception handling is a run time concern, while unit tests are a build time concern.
The two can work together. For example, let's say you have a utility that attempts to move files from one place to another, and verify that they are bit for bit the same. In your utility, you need to scan for the available files, and then work on them one by one.
A number of things can cause the utility to not be able to copy a file:
- The file is in use by another process
- You do not have permissions to delete the file from its present location, or write it to the destination
- If you have more than one utility running at once, the file could be gone by the time you get to it in your loop
Those are all exceptions. You have to decide whether any of those exceptions should cause your utility to stop processing. For example, the final exception is something we don't want to stop prematurely with, and it is probably OK to skip a file if another process has it. The permissions thing really prevents your utility from doing its job, so you'll need to stop if that's the case.
In your unit tests, you would set up a scenario where each of those conditions would be met, and then assert that the application behaves appropriately:
- Unit test 1 sets up a source and destination directory where everything is set up for a successful copy. It works, no exception handling required!
- Unit test 2 sets up a source and destination directory, and then puts a lock on the source file. It fails, so you need to add exception handling to your utility to handle the lock (i.e. skip the existing file and move on
- Unit test 3-5 sets up source and destination directory and a source file, but changes the permissions (source, destination, both) and asserts that the utility stops as soon as it realizes it can't copy any files. If the exception handling you put in before isn't too broad, then this should work. If not, you have to change your application to make all the tests pass.
- Unit test 6 would be a bit more difficult to instrument since you would need to know when the source directory scan is complete, but it would set up source and destination directories, source file and then delete the source file after the scan is complete but before the move operation was performed. If the application ends early it fails, so you need to add exception handling, or at least an
existscheck before the copy/verify/delete operation is complete.
As you can see they are not mutually exclusive concepts to improve your application. However, they serve very different purposes.
I will say using exception handling where a simple if statement is more appropriate, you should change your code. In the example you provided there was a snippet that looked like this:
try:
assert self.turn >= 0
except ValueError:
print('turn number must be positive')
That would be a misapplication of an assert, particularly because you are not letting the exception leave the method. That could would be much cleaner, and execute faster (especially in loops) like this:
if selt.turn < 0:
print('turn number must be positive')
That code provides the same effect in a more readable way, that doesn't have the overhead of exception handling. Exception handling is expensive.
Now, if you wanted that to be an exceptional case that stops the game because now the game is in an undetermined state, you should not catch the exception in that code, and let whoever is calling the code deal with it. That would simply look like this:
assert(self.turn >= 0, 'turn number must be positive')
Hi all, I've written an error-handling function called prettify_error. This function is called in a few try-except blocks when doing some file work, such as reading or writing. So, the function takes in an Exception and an optional file_mode parameter. I did this to make the function more robust in case I have to call it in the future with doing other things that could throw an exception. Anyway, here's the function code:
def prettify_error(error: Exception, file_mode: str = ""):
"""Helper function to prettify an error or exception
This function will take an Exception and create a more human-readable
output for the error
Args:
error (Exception): The Exception that was caught (might be most likely
through a try-except block).
file_mode (str, optional): If the Exception was caught while working
with files, this parameter will tell which file mode or what action was
being taken. Acceptable values are "r" for reading, "w" for writing.
Defaults to "". If the default value is used or a non-acceptable value
is used, only the Exception will be returned without any extra
messaging.
Returns:
str: The Exception printed out in a way that makes sense
"""
return_message = ""
match file_mode:
case "r":
return_message += "Unable to read startup data. Error information is below:\n"
case "w":
return_message += "Unable to write startup data. Error information is below:\n"
case _:
pass
return_message += str(type(error).__name__) + " - " + str(error)
return return_message
I'm now trying to write unittest test functions for it but I'm not sure how to call it. I looked up some stuff and I read about the unittest self.assertRaises function as well as creating custom Exception classes that extend the base class. But, I don't think the first will work since I'm really testing for the return_message variable and will be using self.assertEquals instead. I'm also going to have 3 test functions, one for a file_mode value of default, one for a value of "r", and one for a value of "w". I also feel like creating a customer Exception class is overkill.
What do you think? Is that the best way to test prettify_error, by creating a custom Exception class and passing that in during my tests? Or can I pass in a specific Exception, like Exception.TypeError?
Thanks in advance.