user992570
user992570

Reputation: 101

How to mock MongoClient for python unit test?

I have following piece of code to UT, which makes me in trouble:

  def initialize():
    try :
        self.client = MongoClient("127.0.0.1", 27017)
        self.conn = self.client["DB_NAME"]
    except Exception:
        print "Except in initialize!"
        return False
    return True

I write following test case to cover the above function, hope to get return value "True":

def mock_mongodb_mongoclient_init(self, para1, para2):
    pass

def mock_mongodb_mongoclient_getitem(self, name):
    return {"DB_NAME":"Something"}

def test_mongodb_initialize_true(self):
    self.patcher1 = patch('pymongo.MongoClient.__init__', new=self.mock_mongodb_mongoclient_init)
    self.patcher2 = patch('pymongo.MongoClient.__getitem__', new=self.mock_mongodb_mongoclient_getitem)
    self.patcher1.start()
    self.patcher2.start()
    self.assertEqual(initialize(), True)
    self.patcher1.stop()
    self.patcher2.stop()

But this never works! It always report "Exception in initialize!"! and return "False".

How could I UT this MongoClient and makes the function return "True"?

Upvotes: 3

Views: 7815

Answers (3)

Pedro Jiménez
Pedro Jiménez

Reputation: 499

Since you are unit testing and not trying to actually connect to Mongo in any way, I think you should just care that the client API has been called. So I would suggest the following -

from unittest import mock
@mock.patch("pymongo.MongoClient")
def test_mongodb_initialize(self, mock_pymongo):
    MyMongo.initialize()
    self.assertTrue(mock_pymongo.called)

(Forgive me if my syntax is off, I use pytest rather than unittest.)

Upvotes: 1

A. Jesse Jiryu Davis
A. Jesse Jiryu Davis

Reputation: 24007

MongoClient is not designed to be mocked this way. It must initialize its attributes in __init__ in order to function, so if you skip calling __init__, all further operations will throw various exceptions. In your specific case, MongoClient needs access to the __slave_okay attribute, but it isn't set.

Either set up an actual MongoDB server and test against it, or mock all of PyMongo with a fake library. Simply overriding a handful of methods in PyMongo is not going to work with reasonable effort.

Upvotes: 0

clsung
clsung

Reputation: 1738

For simply pass the initialize(), we can mock the pymongo.MongoClient as following:

import unittest
import pymongo
from mock import patch


class MyMongo(object):
    def initialize(self):
        try :
            self.client = pymongo.MongoClient("127.0.0.1", 27017)
            self.conn = self.client["DB_NAME"]
        except Exception:
            print "Except in initialize!"
            return False
        return True


class TestMyMongo(unittest.TestCase):
    def test_mongodb_initialize_true(self):
        with patch('pymongo.MongoClient') as mock_mongo:
            self.mymongo = MyMongo()
            self.assertEqual(self.mymongo.initialize(), True)

However I'm not sure if you're trying to mock the MongoClient or just the MongoClient.init part?

Upvotes: 0

Related Questions