4

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

1
  • The issue is that you define db = Database('zset') on module import, so your mock patch does not affect your db variable. Commented Apr 19, 2020 at 14:27

1 Answer 1

5

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Nope not working, it is still calling the original code. Also app.py is a flask app, does that affect on the way I should test my application?
It shouldn't make a difference, although for the test case you have posted, my test function calls the mocked version. Maybe you are missing some detail about your implementation?
I have updated my question with exact same code that I have running at my end. I hope this helps.
I tried your exact source code with my updated test function and it worked. Is the test_add_word function a method of a class? If yes can you post this class? Also I thought that maybe the double usage of app as your flask app and as the module name might cause an issue, although it worked for me.
I have updated the question with my test code too. I hope this helps as this is making me crazy now. :(
|

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.