8

I followed the Django doc to write tests with assertRaisesMessage() but the problem is the exception itself is raised when executing test (so, the test is not executed). Note that the exception called is an exception I voluntarily raise in a method of my model (not in the view).

class MyTestCase(TestCase):
    def test_invertRewardState_view_fails_notmy_reward(self):
        self.client.login(email='[email protected]', password='azerty')
        resp = self.client.get(reverse(invertRewardState, args=(1,)))
        self.assertRaisesMessage(
            expected_exception=Exception,
            expected_message=EXC_NOT_YOURS,
            callable_obj=resp)

How Should I use AssertRaisesMessage() to let my test be executed without raising the Exception? Thanks.

EDIT : After trying falsetru 1st solution, the problem is still the same. As soon as my test enters in the resp = ... part, view is called, then related model method is called and raises the exception. the full stack trace :

Traceback (most recent call last):
  File "/Users/walt/Code/hellodjango/clientizr/tests.py", line 338, in test_invertRewardState_view_fails_notmy_reward
    resp = self.client.get(reverse(invertRewardState, args=('1',)))
  File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/test/client.py", line 473, in get
    response = super(Client, self).get(path, data=data, **extra)
  File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/test/client.py", line 280, in get
    return self.request(**r)
  File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/test/client.py", line 444, in request
    six.reraise(*exc_info)
  File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 114, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/walt/Code/hellodjango/venv/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 22, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/Users/walt/Code/hellodjango/clientizr/views.py", line 234, in invertRewardState
    reward.invert_reward_state(request.user)
  File "/Users/walt/Code/hellodjango/clientizr/models.py", line 606, in invert_reward_state
    self.throw_error_if_not_owner_reward(cur_user)
  File "/Users/walt/Code/hellodjango/clientizr/models.py", line 587, in throw_error_if_not_owner_reward
    raise Exception(EXC_NOT_YOURS)
Exception: Cet objet n'est pas le v\xf4tre
2
  • From what part do you expect get an expcetion? self.client.get()? Commented Aug 13, 2014 at 13:36
  • The invertRewardState view call a method in my models.py that raises an Exception. I know I'm coupling stuff here (not really good for unit tests), but I need to know that the view does not work if the case the arg passed to the view ('1' in my example) is not an object owned by the logged user. Commented Aug 13, 2014 at 13:54

2 Answers 2

14

You use assertRaisesMessage as a context manager around the code you expect to fail:

class MyTestCase(TestCase):
    def test_invertRewardState_view_fails_notmy_reward(self):
        self.client.login(email='[email protected]', password='azerty')
        url = reverse(invertRewardState, args=(1,))
        with self.assertRaisesMessage(Exception, EXC_NOT_YOURS):
            self.client.get(url)
Sign up to request clarification or add additional context in comments.

3 Comments

Thx it works this way. What should I need to change in your code if I want to test only the HTTP code response (500 ?
@DavidW. If this answer worked for you (it has been over a year), shouldn't you mark it as accepted?
@NedBatchelder that's embarrassing. I read so fast I thought Aug 13 was Aug 2013... too many 13s in that timestamp.
1

If you use self.client.get, you will not get an exception directly, but you can check status code.

def test_invertRewardState_view_fails_notmy_reward(self):
    self.client.login(email='[email protected]', password='azerty')
    resp = self.client.get(reverse(invertRewardState, args=('1',)))
    self.assertEqual(resp.status_code, 500)
    self.assertIn(EXC_NOT_YOURS in resp.content)

If you want to get an exception, call the view directly.

def test_invertRewardState_view_fails_notmy_reward(self):
    request = HttpRequest()
    request.user = User.objects.create(email='[email protected]')  # login
    self.assertRaisesMessage(Exception, EXC_NOT_YOURS, invertRewardState, '1')

You can use context manager form as Ned Batchelder suggested.

5 Comments

Thanks for this! About what I said bedfore, do you think a better approach would be to only test the status code in the view (ie. 500 expected), then make another test for the model and in this one test the Exception raised? The purpose is to avoid coupling stuff.
@DavidW., I have no strong opinion about it.
Actually I tried the first solution but it doesn't work. The line resp = client..raises the exception when the test is executed :(
@DavidW., What was the exception? Could you post the full traceback somewhere? (not in comment)
The exception is one I volontary raise in a method of my model. I updated the stack trace. As you can see, the view is called, so my model method is called, and the exception is logically raised

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.