Reputation: 8372
I want to write a test to establish that an Exception is not raised in a given circumstance.
It's straightforward to test if an Exception is raised ...
sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath)
... but how can you do the opposite.
Something like this i what I'm after ...
sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath)
Upvotes: 524
Views: 216618
Reputation: 471
My solution - derived from accepted solution: Cache error on function. If there is no error, Assertion error will raise. In that case -> test Passed! Else, write error message.
Code:
try:
with self.assertRaises((PathIsNotAValidOne, AnotherError)) as err:
AlwaysSuppliesAnInvalidPath()
error = str(err.exception)
except AssertionError:
self.assertTrue(True)
else:
self.fail(error)
And:
try:
with self.assertRaises((PathIsNotAValidOne, AnotherError)) as err:
AlwaysSuppliesAValidPath()
error = str(err.exception)
except AssertionError:
self.assertTrue(True)
else:
self.fail(error)
Little twisted logic, but works as a charm!
Upvotes: 0
Reputation: 11102
Just call the function. If it raises an exception, the unit test framework will flag this as an error. You might like to add a comment, e.g.:
sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)
Edited to add clarifications from the comments:
Upvotes: 59
Reputation: 7
One straight forward way to ensure the object is initialized without any error is to test the object's type instance.
Here is an example :
p = SomeClass(param1=_param1_value)
self.assertTrue(isinstance(p, SomeClass))
Upvotes: -2
Reputation: 161
def _assertNotRaises(self, exception, obj, attr):
try:
result = getattr(obj, attr)
if hasattr(result, '__call__'):
result()
except Exception as e:
if isinstance(e, exception):
raise AssertionError('{}.{} raises {}.'.format(obj, attr, exception))
could be modified if you need to accept parameters.
call like
self._assertNotRaises(IndexError, array, 'sort')
Upvotes: 3
Reputation: 41
you can try like that. try: self.assertRaises(None,function,arg1, arg2) except: pass if you don't put code inside try block it will through exception' AssertionError: None not raised " and test case will be failed. Test case will be pass if put inside try block which is expected behaviour.
Upvotes: 1
Reputation: 13997
You can define assertNotRaises
by reusing about 90% of the original implementation of assertRaises
in the unittest
module. With this approach, you end up with an assertNotRaises
method that, aside from its reversed failure condition, behaves identically to assertRaises
.
It turns out to be surprisingly easy to add an assertNotRaises
method to unittest.TestCase
(it took me about 4 times as long to write this answer as it did the code). Here's a live demo of the assertNotRaises
method in action. Just like assertRaises
, you can either pass a callable and args to assertNotRaises
, or you can use it in a with
statement. The live demo includes a test cases that demonstrates that assertNotRaises
works as intended.
The implementation of assertRaises
in unittest
is fairly complicated, but with a little bit of clever subclassing you can override and reverse its failure condition.
assertRaises
is a short method that basically just creates an instance of the unittest.case._AssertRaisesContext
class and returns it (see its definition in the unittest.case
module). You can define your own _AssertNotRaisesContext
class by subclassing _AssertRaisesContext
and overriding its __exit__
method:
import traceback
from unittest.case import _AssertRaisesContext
class _AssertNotRaisesContext(_AssertRaisesContext):
def __exit__(self, exc_type, exc_value, tb):
if exc_type is not None:
self.exception = exc_value.with_traceback(None)
try:
exc_name = self.expected.__name__
except AttributeError:
exc_name = str(self.expected)
if self.obj_name:
self._raiseFailure("{} raised by {}".format(exc_name,
self.obj_name))
else:
self._raiseFailure("{} raised".format(exc_name))
else:
traceback.clear_frames(tb)
return True
Normally you define test case classes by having them inherit from TestCase
. If you instead inherit from a subclass MyTestCase
:
class MyTestCase(unittest.TestCase):
def assertNotRaises(self, expected_exception, *args, **kwargs):
context = _AssertNotRaisesContext(expected_exception, self)
try:
return context.handle('assertNotRaises', args, kwargs)
finally:
context = None
all of your test cases will now have the assertNotRaises
method available to them.
Upvotes: 22
Reputation: 11549
def run_test(self):
try:
myFunc()
except ExceptionType:
self.fail("myFunc() raised ExceptionType unexpectedly!")
Upvotes: 579
Reputation: 1133
I've found it useful to monkey-patch unittest
as follows:
def assertMayRaise(self, exception, expr):
if exception is None:
try:
expr()
except:
info = sys.exc_info()
self.fail('%s raised' % repr(info[0]))
else:
self.assertRaises(exception, expr)
unittest.TestCase.assertMayRaise = assertMayRaise
This clarifies intent when testing for the absence of an exception:
self.assertMayRaise(None, does_not_raise)
This also simplifies testing in a loop, which I often find myself doing:
# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))
Upvotes: 3
Reputation: 454
If you pass an Exception class to assertRaises()
, a context manager is provided. This can improve the readability of your tests:
# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
application = Application("abcdef", "")
This allows you to test error cases in your code.
In this case, you are testing the PathIsNotAValidOne
is raised when you pass invalid parameters to the Application constructor.
Upvotes: 1
Reputation: 8372
I am the original poster and I accepted the above answer by DGH without having first used it in the code.
Once I did use I realised that it needed a little tweaking to actually do what I needed it to do (to be fair to DGH he/she did say "or something similar" !).
I thought it was worth posting the tweak here for the benefit of others:
try:
a = Application("abcdef", "")
except pySourceAidExceptions.PathIsNotAValidOne:
pass
except:
self.assertTrue(False)
What I was attempting to do here was to ensure that if an attempt was made to instantiate an Application object with a second argument of spaces the pySourceAidExceptions.PathIsNotAValidOne would be raised.
I believe that using the above code (based heavily on DGH's answer) will do that.
Upvotes: 19
Reputation: 392010
Hi - I want to write a test to establish that an Exception is not raised in a given circumstance.
That's the default assumption -- exceptions are not raised.
If you say nothing else, that's assumed in every single test.
You don't have to actually write an any assertion for that.
Upvotes: 91