5

I'm trying to write a unittest that will check if the correct error message is returned in case the database connection hits exception. I've tried to use connection.creation.destroy_test_db(':memory:') but it didn't work as I expected. I suppose I should either remove the tables or somehow cut the db connection. Is any of those possible?

3
  • 1
    Maybe you can raise a DatabaseError and catch it. from django.db import DatabaseError raise DatabaseError Here the list of default django exceptions docs.djangoproject.com/en/dev/ref/exceptions Commented May 12, 2013 at 13:42
  • I am confused. The question is titled "without connection", but in the body you said you are trying to assert the message is returned when there's an exception. Like what? Duplicate key? The title and the body don't quite match and I am just confused. Clarification? Commented May 12, 2013 at 20:08
  • 1
    No connection to the database raises DatabaseError exception, which is what I'm trying to cause and assert the error message my webapp prints in this case Commented Jun 8, 2013 at 19:18

4 Answers 4

5

I found my answer in the presentation Testing and Django by Carl Meyer. Here is how I did it:

from django.db import DatabaseError
from django.test import TestCase
from django.test.client import Client
import mock

class NoDBTest(TestCase):
    cursor_wrapper = mock.Mock()
    cursor_wrapper.side_effect = DatabaseError

    @mock.patch("django.db.backends.util.CursorWrapper", cursor_wrapper)
    def test_no_database_connection(self):
        response = self.client.post('/signup/', form_data)
        self.assertEqual(message, 'An error occured with the DB')
Sign up to request clarification or add additional context in comments.

Comments

3

Sounds like this is a job for mocking. For example, if you are using MySQL, you can put a side_effect on connect method, like this:

from django.test import TestCase
from mock import patch
import MySQLdb


class DBTestCase(TestCase):
    def test_connection_error(self):
        with patch.object(MySQLdb, 'connect') as connect_method:
            connect_method.side_effect = Exception("Database Connection Error")

            # your assertions here

Hope that helps.

1 Comment

thanks for the reply! I did it slightly different, see my answer.
2

Since dec, 2021 there is the library Django Mockingbird.

With this you can mock the object that would be retrieved from db.

from djangomockingbird import mock_model

@mock_model('myapp.myfile.MyModel')
def test_my_test():
    some_test_query = MyModel.objects.filter(bar='bar').filter.(foo='foo').first()
    #some more code
    #assertions here

Comments

2

I was looking for django's actual http response code in case of a database connection timeout when using pymysql. The following test confirmed it's a 401 Unauthorized when pymysql raises an OperationalError.

from unittest.mock import patch

import pymysql
from django.test import TestCase, Client


class TestDatabaseOutage(TestCase):
    client = None

    def setUp(self):
        self.client = Client()

    def test_database_connection_timeout_returns_401(self):
        with patch.object(pymysql, 'connect') as connect_method:
            message = "Can't connect to MySQL server on 'some_database.example.com' ([Errno 110] Connection timed out)"
            connect_method.side_effect = pymysql.OperationalError(2003, message)
            response = self.client.get('/')
            self.assertEqual(response.status_code, 401)

401 Unauthorized http cat

Comments

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.