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