tampakrap
tampakrap

Reputation: 111

django unittest without database connection

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?

Upvotes: 5

Views: 3692

Answers (4)

Eduardo Tolmasquim
Eduardo Tolmasquim

Reputation: 404

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

Upvotes: 2

GabLeRoux
GabLeRoux

Reputation: 17923

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

Upvotes: 2

tampakrap
tampakrap

Reputation: 111

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')

Upvotes: 5

alecxe
alecxe

Reputation: 473833

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.

Upvotes: 3

Related Questions