Reputation: 615
I have the following validation function in my model:
@classmethod
def validate_kind(cls, kind):
if kind == 'test':
raise ValidationError("Invalid question kind")
which I am trying to test as follows:
w = Model.objects.get(id=1)
self.assertRaises(ValidationError, w.validate_kind('test'),msg='Invalid question kind')
I also tried:
self.assertRaisesRegex(w.validate_kind('test'),'Invalid question kind')
Both of these don't work correctly. What am I doing wrong?
Upvotes: 12
Views: 15744
Reputation: 15289
Do not use assertRaises
to check the message, because it doesn't do what you think it does.
Use assertRaisesMessage
instead:
with self.assertRaisesMessage(ValidationError, "Invalid question kind"):
w.validate_kind('test')
This will assert that "Invalid question kind"
is in the error message, which is usually all you want to test (if you want more control, use assertRaisesRegex
).
Why assertRaises is dangerous:
First you need to be aware there are two ways you can use assertRaises
(documented here)
1 - By passing the callable itself:
self.assertRaises(ValidationError, w.validate_kind, 'test')
The args/kwargs after the callable are passed to the callable, so there's no way to check the message.
2 - By using as a context:
with self.assertRaises(ValidationError, msg='Invalid question kind'):
w.validate_kind('test')
Here msg
is simply set on the captured exception, so you can use it later. It does not check the message in the error raised by your function, and so the test will pass even if the messages don't match.
Try it and see:
def foo():
raise ValidationError('abc')
def test_foo():
with self.assertRaises(ValidationError, msg='xyz') as e:
foo()
print(e.exception, e.msg)
The test will pass and you'll see the following print out:
abc xyz
.
-------------------------------
Ran 1 test in 0.002s
That's one of the reasons why in TDD they always advise you to write a test that fails first, and then make it pass.
For more info, read Django's testing docs
Upvotes: 0
Reputation: 56
I would do:
with self.assertRaises(ValidationError, msg='Invalid question kind'):
w.validate_kind('test')
This may well be a change in Python since the question was originally asked.
Upvotes: 3
Reputation: 31404
The way you are calling assertRaises
is wrong - you need to pass a callable instead of calling the function itself, and pass any arguments to the function as arguments to assertRaises
. Change it to:
self.assertRaises(ValidationError, w.validate_kind, 'test')
Upvotes: 31
Reputation: 136
The accepted answer isn't correct. self.assertRaises()
doesn't check the exception message.
If you want to assert the exception message, you should use self.assertRaisesRegex().
self.assertRaisesRegex(ValidationError, 'Invalid question kind', w.validate_kind, 'test')
or
with self.assertRaisesRegex(ValidationError, 'Invalid question kind'):
w.validate_kind('test')
Upvotes: 8