shivams
shivams

Reputation: 2717

Mock database connection python

I have a file called redis_db.py which has code to connect to redis

import os
import redis
import sys

class Database:
       def __init__(self, zset_name):
        redis_host = os.environ.get('REDIS_HOST', '127.0.0.1')
        redis_port = os.environ.get('REDIS_PORT', 6379)

        self.db = redis.StrictRedis(host=redis_host, port=redis_port)
        self.zset_name = zset_name

    def add(self, key):
        try:
            self.db.zadd(self.zset_name, {key: 0})
        except redis.exceptions.ConnectionError:
            print("Unable to connect to redis host.")
            sys.exit(0)

I have another file called app.py which is like this

from flask import Flask
from redis_db import Database

app = Flask(__name__)
db = Database('zset')

@app.route('/add_word/word=<word>')
def add_word(word):
   db.add(word)
   return ("{} added".format(word))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port='8080')

Now I am writing unit test for add_word function like this

import unittest
import sys
import os
from unittest import mock

sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../api/")
from api import app  # noqa: E402


class Testing(unittest.TestCase):

  def test_add_word(self):
      with mock.patch('app.Database') as mockdb:
         mockdb.return_value.add.return_value = ""
      result = app.add_word('shivam')
      self.assertEqual(result, 'shivam word added.')

Issue I am facing is that even though I am mocking the db method call it is still calling the actual method in the class instead of returning mocked values and during testing I am getting error with message Unable to connect to redis host..

Can someone please help me in figuring out how can I mock the redis database calls.

I am using unittest module

Upvotes: 4

Views: 18338

Answers (1)

Erich
Erich

Reputation: 1848

The issue is that db is defined on module import, so the mock.patch does not affect the db variable. Either you move the instantiation of db in the add_word(word) function or you patch db instead of Database, e.g.

def test_add_word():
    with mock.patch('api.app.db') as mockdb:
        mockdb.add = mock.MagicMock(return_value="your desired return value")
        result = app.add_word('shivam')
    print(result)

Note that the call of add_word has to be in the with block, otherwise the unmocked version is used.

Upvotes: 5

Related Questions